Example #1
0
 /**
  * Returns an instance of the cache_helper.
  *
  * This is designed for internal use only and acts as a static store.
  * @staticvar null $instance
  * @return cache_helper
  */
 protected static function instance()
 {
     if (is_null(self::$instance)) {
         self::$instance = new cache_helper();
     }
     return self::$instance;
 }
Example #2
0
 public static function create_group($group)
 {
     global $DB, $CFG;
     // Valida os parametros.
     $params = self::validate_parameters(self::create_group_parameters(), array('group' => $group));
     // Transforma o array em objeto.
     $group = (object) $group;
     // Inicia a transacao, qualquer erro que aconteca o rollback sera executado.
     $transaction = $DB->start_delegated_transaction();
     // Busca o id do curso apartir do trm_id da turma.
     $courseid = self::get_course_by_trm_id($group->trm_id);
     // Se nao existir curso mapeado para a turma dispara uma excessao.
     if (!$courseid) {
         throw new Exception("Nenhum curso mapeado com a turma com trm_id: " . $group->trm_id);
     }
     $groupbyname = self::get_group_by_name($courseid, $group->name);
     // Dispara uma excessao caso ja exista um grupo com o mesmo nome no mesmo curso
     if ($groupbyname) {
         throw new Exception("ja existe um grupo com o mesmo nome nessa turma trm_id: " . $group->trm_id);
     }
     $groupdata['courseid'] = $courseid;
     $groupdata['name'] = $group->name;
     $groupdata['description'] = $group->description;
     $groupdata['descriptionformat'] = 1;
     $groupdata['timecreated'] = time();
     $groupdata['timemodified'] = $groupdata['timecreated'];
     $resultid = $DB->insert_record('groups', $groupdata);
     // Caso o curso tenha sido criado adiciona a tabela de controle os dados dos curso e da turma.
     if ($resultid) {
         $data['trm_id'] = $group->trm_id;
         $data['grp_id'] = $group->grp_id;
         $data['groupid'] = $resultid;
         $res = $DB->insert_record('itg_grupo_group', $data);
         // Busca as configuracoes do curso
         $courseoptions = $DB->get_record('course', array('id' => $courseid), '*');
         // Altera o formato de grupos do curso
         $courseoptions->groupmode = 1;
         $courseoptions->groupmodeforce = 1;
         $DB->update_record('course', $courseoptions);
         // Invalidate the grouping cache for the course
         cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
         // Prepara o array de retorno.
         $returndata = null;
         if ($res) {
             $returndata['id'] = $resultid;
             $returndata['status'] = 'success';
             $returndata['message'] = 'Grupo criado com sucesso';
         } else {
             $returndata['id'] = 0;
             $returndata['status'] = 'error';
             $returndata['message'] = 'Erro ao tentar criar o grupo';
         }
     }
     // Persiste as operacoes em caso de sucesso.
     $transaction->allow_commit();
     return $returndata;
 }
Example #3
0
/**
 * Execute cron tasks
 */
function cron_run()
{
    global $DB, $CFG, $OUTPUT;
    if (CLI_MAINTENANCE) {
        echo "CLI maintenance mode active, cron execution suspended.\n";
        exit(1);
    }
    if (moodle_needs_upgrading()) {
        echo "Moodle upgrade pending, cron execution suspended.\n";
        exit(1);
    }
    require_once $CFG->libdir . '/adminlib.php';
    require_once $CFG->libdir . '/gradelib.php';
    if (!empty($CFG->showcronsql)) {
        $DB->set_debug(true);
    }
    if (!empty($CFG->showcrondebugging)) {
        set_debugging(DEBUG_DEVELOPER, true);
    }
    set_time_limit(0);
    $starttime = microtime();
    // Increase memory limit
    raise_memory_limit(MEMORY_EXTRA);
    // Emulate normal session - we use admin accoutn by default
    cron_setup_user();
    // Start output log
    $timenow = time();
    mtrace("Server Time: " . date('r', $timenow) . "\n\n");
    // Run cleanup core cron jobs, but not every time since they aren't too important.
    // These don't have a timer to reduce load, so we'll use a random number
    // to randomly choose the percentage of times we should run these jobs.
    $random100 = rand(0, 100);
    if ($random100 < 20) {
        // Approximately 20% of the time.
        mtrace("Running clean-up tasks...");
        cron_trace_time_and_memory();
        // Delete users who haven't confirmed within required period
        if (!empty($CFG->deleteunconfirmed)) {
            $cuttime = $timenow - $CFG->deleteunconfirmed * 3600;
            $rs = $DB->get_recordset_sql("SELECT *\n                                             FROM {user}\n                                            WHERE confirmed = 0 AND firstaccess > 0\n                                                  AND firstaccess < ?", array($cuttime));
            foreach ($rs as $user) {
                delete_user($user);
                // we MUST delete user properly first
                $DB->delete_records('user', array('id' => $user->id));
                // this is a bloody hack, but it might work
                mtrace(" Deleted unconfirmed user for " . fullname($user, true) . " ({$user->id})");
            }
            $rs->close();
        }
        // Delete users who haven't completed profile within required period
        if (!empty($CFG->deleteincompleteusers)) {
            $cuttime = $timenow - $CFG->deleteincompleteusers * 3600;
            $rs = $DB->get_recordset_sql("SELECT *\n                                             FROM {user}\n                                            WHERE confirmed = 1 AND lastaccess > 0\n                                                  AND lastaccess < ? AND deleted = 0\n                                                  AND (lastname = '' OR firstname = '' OR email = '')", array($cuttime));
            foreach ($rs as $user) {
                if (isguestuser($user) or is_siteadmin($user)) {
                    continue;
                }
                delete_user($user);
                mtrace(" Deleted not fully setup user {$user->username} ({$user->id})");
            }
            $rs->close();
        }
        // Delete old logs to save space (this might need a timer to slow it down...)
        if (!empty($CFG->loglifetime)) {
            // value in days
            $loglifetime = $timenow - $CFG->loglifetime * 3600 * 24;
            $DB->delete_records_select("log", "time < ?", array($loglifetime));
            mtrace(" Deleted old log records");
        }
        // Delete old backup_controllers and logs.
        $loglifetime = get_config('backup', 'loglifetime');
        if (!empty($loglifetime)) {
            // Value in days.
            $loglifetime = $timenow - $loglifetime * 3600 * 24;
            // Delete child records from backup_logs.
            $DB->execute("DELETE FROM {backup_logs}\n                           WHERE EXISTS (\n                               SELECT 'x'\n                                 FROM {backup_controllers} bc\n                                WHERE bc.backupid = {backup_logs}.backupid\n                                  AND bc.timecreated < ?)", array($loglifetime));
            // Delete records from backup_controllers.
            $DB->execute("DELETE FROM {backup_controllers}\n                          WHERE timecreated < ?", array($loglifetime));
            mtrace(" Deleted old backup records");
        }
        // Delete old cached texts
        if (!empty($CFG->cachetext)) {
            // Defined in config.php
            $cachelifetime = time() - $CFG->cachetext - 60;
            // Add an extra minute to allow for really heavy sites
            $DB->delete_records_select('cache_text', "timemodified < ?", array($cachelifetime));
            mtrace(" Deleted old cache_text records");
        }
        if (!empty($CFG->usetags)) {
            require_once $CFG->dirroot . '/tag/lib.php';
            tag_cron();
            mtrace(' Executed tag cron');
        }
        // Context maintenance stuff
        context_helper::cleanup_instances();
        mtrace(' Cleaned up context instances');
        context_helper::build_all_paths(false);
        // If you suspect that the context paths are somehow corrupt
        // replace the line below with: context_helper::build_all_paths(true);
        mtrace(' Built context paths');
        // Remove expired cache flags
        gc_cache_flags();
        mtrace(' Cleaned cache flags');
        // Cleanup messaging
        if (!empty($CFG->messagingdeletereadnotificationsdelay)) {
            $notificationdeletetime = time() - $CFG->messagingdeletereadnotificationsdelay;
            $DB->delete_records_select('message_read', 'notification=1 AND timeread<:notificationdeletetime', array('notificationdeletetime' => $notificationdeletetime));
            mtrace(' Cleaned up read notifications');
        }
        mtrace(' Deleting temporary files...');
        cron_delete_from_temp();
        // Cleanup user password reset records
        // Delete any reset request records which are expired by more than a day.
        // (We keep recently expired requests around so we can give a different error msg to users who
        // are trying to user a recently expired reset attempt).
        $pwresettime = isset($CFG->pwresettime) ? $CFG->pwresettime : 1800;
        $earliestvalid = time() - $pwresettime - DAYSECS;
        $DB->delete_records_select('user_password_resets', "timerequested < ?", array($earliestvalid));
        mtrace(' Cleaned up old password reset records');
        mtrace("...finished clean-up tasks");
    }
    // End of occasional clean-up tasks
    // Send login failures notification - brute force protection in moodle is weak,
    // we should at least send notices early in each cron execution
    if (notify_login_failures()) {
        mtrace(' Notified login failures');
    }
    // Make sure all context instances are properly created - they may be required in auth, enrol, etc.
    context_helper::create_instances();
    mtrace(' Created missing context instances');
    // Session gc.
    mtrace("Running session gc tasks...");
    \core\session\manager::gc();
    mtrace("...finished stale session cleanup");
    // Run the auth cron, if any before enrolments
    // because it might add users that will be needed in enrol plugins
    $auths = get_enabled_auth_plugins();
    mtrace("Running auth crons if required...");
    cron_trace_time_and_memory();
    foreach ($auths as $auth) {
        $authplugin = get_auth_plugin($auth);
        if (method_exists($authplugin, 'cron')) {
            mtrace("Running cron for auth/{$auth}...");
            $authplugin->cron();
            if (!empty($authplugin->log)) {
                mtrace($authplugin->log);
            }
        }
        unset($authplugin);
    }
    // Generate new password emails for users - ppl expect these generated asap
    if ($DB->count_records('user_preferences', array('name' => 'create_password', 'value' => '1'))) {
        mtrace('Creating passwords for new users...');
        $usernamefields = get_all_user_name_fields(true, 'u');
        $newusers = $DB->get_recordset_sql("SELECT u.id as id, u.email,\n                                                 {$usernamefields}, u.username, u.lang,\n                                                 p.id as prefid\n                                            FROM {user} u\n                                            JOIN {user_preferences} p ON u.id=p.userid\n                                           WHERE p.name='create_password' AND p.value='1' AND u.email !='' AND u.suspended = 0 AND u.auth != 'nologin' AND u.deleted = 0");
        // note: we can not send emails to suspended accounts
        foreach ($newusers as $newuser) {
            // Use a low cost factor when generating bcrypt hash otherwise
            // hashing would be slow when emailing lots of users. Hashes
            // will be automatically updated to a higher cost factor the first
            // time the user logs in.
            if (setnew_password_and_mail($newuser, true)) {
                unset_user_preference('create_password', $newuser);
                set_user_preference('auth_forcepasswordchange', 1, $newuser);
            } else {
                trigger_error("Could not create and mail new user password!");
            }
        }
        $newusers->close();
    }
    // It is very important to run enrol early
    // because other plugins depend on correct enrolment info.
    mtrace("Running enrol crons if required...");
    $enrols = enrol_get_plugins(true);
    foreach ($enrols as $ename => $enrol) {
        // do this for all plugins, disabled plugins might want to cleanup stuff such as roles
        if (!$enrol->is_cron_required()) {
            continue;
        }
        mtrace("Running cron for enrol_{$ename}...");
        cron_trace_time_and_memory();
        $enrol->cron();
        $enrol->set_config('lastcron', time());
    }
    // Run all cron jobs for each module
    mtrace("Starting activity modules");
    get_mailer('buffer');
    if ($mods = $DB->get_records_select("modules", "cron > 0 AND ((? - lastcron) > cron) AND visible = 1", array($timenow))) {
        foreach ($mods as $mod) {
            $libfile = "{$CFG->dirroot}/mod/{$mod->name}/lib.php";
            if (file_exists($libfile)) {
                include_once $libfile;
                $cron_function = $mod->name . "_cron";
                if (function_exists($cron_function)) {
                    mtrace("Processing module function {$cron_function} ...", '');
                    cron_trace_time_and_memory();
                    $pre_dbqueries = null;
                    $pre_dbqueries = $DB->perf_get_queries();
                    $pre_time = microtime(1);
                    if ($cron_function()) {
                        $DB->set_field("modules", "lastcron", $timenow, array("id" => $mod->id));
                    }
                    if (isset($pre_dbqueries)) {
                        mtrace("... used " . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries");
                        mtrace("... used " . (microtime(1) - $pre_time) . " seconds");
                    }
                    // Reset possible changes by modules to time_limit. MDL-11597
                    @set_time_limit(0);
                    mtrace("done.");
                }
            }
        }
    }
    get_mailer('close');
    mtrace("Finished activity modules");
    mtrace("Starting blocks");
    if ($blocks = $DB->get_records_select("block", "cron > 0 AND ((? - lastcron) > cron) AND visible = 1", array($timenow))) {
        // We will need the base class.
        require_once $CFG->dirroot . '/blocks/moodleblock.class.php';
        foreach ($blocks as $block) {
            $blockfile = $CFG->dirroot . '/blocks/' . $block->name . '/block_' . $block->name . '.php';
            if (file_exists($blockfile)) {
                require_once $blockfile;
                $classname = 'block_' . $block->name;
                $blockobj = new $classname();
                if (method_exists($blockobj, 'cron')) {
                    mtrace("Processing cron function for " . $block->name . '....', '');
                    cron_trace_time_and_memory();
                    if ($blockobj->cron()) {
                        $DB->set_field('block', 'lastcron', $timenow, array('id' => $block->id));
                    }
                    // Reset possible changes by blocks to time_limit. MDL-11597
                    @set_time_limit(0);
                    mtrace('done.');
                }
            }
        }
    }
    mtrace('Finished blocks');
    mtrace('Starting admin reports');
    cron_execute_plugin_type('report');
    mtrace('Finished admin reports');
    mtrace('Starting main gradebook job...');
    cron_trace_time_and_memory();
    grade_cron();
    mtrace('done.');
    mtrace('Starting processing the event queue...');
    cron_trace_time_and_memory();
    events_cron();
    mtrace('done.');
    if ($CFG->enablecompletion) {
        // Completion cron
        mtrace('Starting the completion cron...');
        cron_trace_time_and_memory();
        require_once $CFG->dirroot . '/completion/cron.php';
        completion_cron();
        mtrace('done');
    }
    if ($CFG->enableportfolios) {
        // Portfolio cron
        mtrace('Starting the portfolio cron...');
        cron_trace_time_and_memory();
        require_once $CFG->libdir . '/portfoliolib.php';
        portfolio_cron();
        mtrace('done');
    }
    //now do plagiarism checks
    require_once $CFG->libdir . '/plagiarismlib.php';
    plagiarism_cron();
    mtrace('Starting course reports');
    cron_execute_plugin_type('coursereport');
    mtrace('Finished course reports');
    // run gradebook import/export/report cron
    mtrace('Starting gradebook plugins');
    cron_execute_plugin_type('gradeimport');
    cron_execute_plugin_type('gradeexport');
    cron_execute_plugin_type('gradereport');
    mtrace('Finished gradebook plugins');
    // run calendar cron
    require_once "{$CFG->dirroot}/calendar/lib.php";
    calendar_cron();
    // Run external blog cron if needed
    if (!empty($CFG->enableblogs) && $CFG->useexternalblogs) {
        require_once $CFG->dirroot . '/blog/lib.php';
        mtrace("Fetching external blog entries...", '');
        cron_trace_time_and_memory();
        $sql = "timefetched < ? OR timefetched = 0";
        $externalblogs = $DB->get_records_select('blog_external', $sql, array(time() - $CFG->externalblogcrontime));
        foreach ($externalblogs as $eb) {
            blog_sync_external_entries($eb);
        }
        mtrace('done.');
    }
    // Run blog associations cleanup
    if (!empty($CFG->enableblogs) && $CFG->useblogassociations) {
        require_once $CFG->dirroot . '/blog/lib.php';
        // delete entries whose contextids no longer exists
        mtrace("Deleting blog associations linked to non-existent contexts...", '');
        cron_trace_time_and_memory();
        $DB->delete_records_select('blog_association', 'contextid NOT IN (SELECT id FROM {context})');
        mtrace('done.');
    }
    // Run question bank clean-up.
    mtrace("Starting the question bank cron...", '');
    cron_trace_time_and_memory();
    require_once $CFG->libdir . '/questionlib.php';
    question_bank::cron();
    mtrace('done.');
    //Run registration updated cron
    mtrace(get_string('siteupdatesstart', 'hub'));
    cron_trace_time_and_memory();
    require_once $CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php';
    $registrationmanager = new registration_manager();
    $registrationmanager->cron();
    mtrace(get_string('siteupdatesend', 'hub'));
    // If enabled, fetch information about available updates and eventually notify site admins
    if (empty($CFG->disableupdatenotifications)) {
        $updateschecker = \core\update\checker::instance();
        $updateschecker->cron();
    }
    //cleanup old session linked tokens
    //deletes the session linked tokens that are over a day old.
    mtrace("Deleting session linked tokens more than one day old...", '');
    cron_trace_time_and_memory();
    $DB->delete_records_select('external_tokens', 'lastaccess < :onedayago AND tokentype = :tokentype', array('onedayago' => time() - DAYSECS, 'tokentype' => EXTERNAL_TOKEN_EMBEDDED));
    mtrace('done.');
    // all other plugins
    cron_execute_plugin_type('message', 'message plugins');
    cron_execute_plugin_type('filter', 'filters');
    cron_execute_plugin_type('editor', 'editors');
    cron_execute_plugin_type('format', 'course formats');
    cron_execute_plugin_type('profilefield', 'profile fields');
    cron_execute_plugin_type('webservice', 'webservices');
    cron_execute_plugin_type('repository', 'repository plugins');
    cron_execute_plugin_type('qbehaviour', 'question behaviours');
    cron_execute_plugin_type('qformat', 'question import/export formats');
    cron_execute_plugin_type('qtype', 'question types');
    cron_execute_plugin_type('plagiarism', 'plagiarism plugins');
    cron_execute_plugin_type('theme', 'themes');
    cron_execute_plugin_type('tool', 'admin tools');
    // and finally run any local cronjobs, if any
    if ($locals = core_component::get_plugin_list('local')) {
        mtrace('Processing customized cron scripts ...', '');
        // new cron functions in lib.php first
        cron_execute_plugin_type('local');
        // legacy cron files are executed directly
        foreach ($locals as $local => $localdir) {
            if (file_exists("{$localdir}/cron.php")) {
                include "{$localdir}/cron.php";
            }
        }
        mtrace('done.');
    }
    mtrace('Running cache cron routines');
    cache_helper::cron();
    mtrace('done.');
    // Run automated backups if required - these may take a long time to execute
    require_once $CFG->dirroot . '/backup/util/includes/backup_includes.php';
    require_once $CFG->dirroot . '/backup/util/helper/backup_cron_helper.class.php';
    backup_cron_automated_helper::run_automated_backup();
    // Run stats as at the end because they are known to take very long time on large sites
    if (!empty($CFG->enablestats) and empty($CFG->disablestatsprocessing)) {
        require_once $CFG->dirroot . '/lib/statslib.php';
        // check we're not before our runtime
        $timetocheck = stats_get_base_daily() + $CFG->statsruntimestarthour * 60 * 60 + $CFG->statsruntimestartminute * 60;
        if (time() > $timetocheck) {
            // process configured number of days as max (defaulting to 31)
            $maxdays = empty($CFG->statsruntimedays) ? 31 : abs($CFG->statsruntimedays);
            if (stats_cron_daily($maxdays)) {
                if (stats_cron_weekly()) {
                    if (stats_cron_monthly()) {
                        stats_clean_old();
                    }
                }
            }
            @set_time_limit(0);
        } else {
            mtrace('Next stats run after:' . userdate($timetocheck));
        }
    }
    // Run badges review cron.
    mtrace("Starting badges cron...");
    require_once $CFG->dirroot . '/badges/cron.php';
    badge_cron();
    mtrace('done.');
    // cleanup file trash - not very important
    $fs = get_file_storage();
    $fs->cron();
    mtrace("Cron script completed correctly");
    gc_collect_cycles();
    mtrace('Cron completed at ' . date('H:i:s') . '. Memory used ' . display_size(memory_get_usage()) . '.');
    $difftime = microtime_diff($starttime, microtime());
    mtrace("Execution took " . $difftime . " seconds");
}
Example #4
0
 /**
  * Sends several key => value pairs to the cache.
  *
  * Using this function comes with potential performance implications.
  * Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
  * the equivalent singular method for each item provided.
  * This should not deter you from using this function as there is a performance benefit in situations where the cache store
  * does support it, but you should be aware of this fact.
  *
  * <code>
  * // This code will add four entries to the cache, one for each url.
  * $cache->set_many(array(
  *     'main' => 'http://moodle.org',
  *     'docs' => 'http://docs.moodle.org',
  *     'tracker' => 'http://tracker.moodle.org',
  *     'qa' => ''http://qa.moodle.net'
  * ));
  * </code>
  *
  * @param array $keyvaluearray An array of key => value pairs to send to the cache.
  * @return int The number of items successfully set. It is up to the developer to check this matches the number of items.
  *      ... if they care that is.
  */
 public function set_many(array $keyvaluearray)
 {
     $this->check_tracked_user();
     $loader = $this->get_loader();
     if ($loader !== false) {
         // We have a loader available set it there as well.
         // We have to let the loader do its own parsing of data as it may be unique.
         $loader->set_many($keyvaluearray);
     }
     $data = array();
     $definitionid = $this->get_definition()->get_ttl();
     $simulatettl = $this->has_a_ttl() && !$this->store_supports_native_ttl();
     foreach ($keyvaluearray as $key => $value) {
         if (is_object($value) && $value instanceof cacheable_object) {
             $value = new cache_cached_object($value);
         } else {
             if (!is_scalar($value)) {
                 // If data is an object it will be a reference.
                 // If data is an array if may contain references.
                 // We want to break references so that the cache cannot be modified outside of itself.
                 // Call the function to unreference it (in the best way possible).
                 $value = $this->unref($value);
             }
         }
         if ($simulatettl) {
             $value = new cache_ttl_wrapper($value, $definitionid);
         }
         $data[$key] = array('key' => $this->parse_key($key), 'value' => $value);
     }
     $successfullyset = $this->get_store()->set_many($data);
     if ($this->perfdebug && $successfullyset) {
         cache_helper::record_cache_set($this->storetype, $definitionid, $successfullyset);
     }
     return $successfullyset;
 }
Example #5
0
/**
 * Main upgrade tasks to be executed on Moodle version bump
 *
 * This function is automatically executed after one bump in the Moodle core
 * version is detected. It's in charge of performing the required tasks
 * to raise core from the previous version to the next one.
 *
 * It's a collection of ordered blocks of code, named "upgrade steps",
 * each one performing one isolated (from the rest of steps) task. Usually
 * tasks involve creating new DB objects or performing manipulation of the
 * information for cleanup/fixup purposes.
 *
 * Each upgrade step has a fixed structure, that can be summarised as follows:
 *
 * if ($oldversion < XXXXXXXXXX.XX) {
 *     // Explanation of the update step, linking to issue in the Tracker if necessary
 *     upgrade_set_timeout(XX); // Optional for big tasks
 *     // Code to execute goes here, usually the XMLDB Editor will
 *     // help you here. See {@link http://docs.moodle.org/dev/XMLDB_editor}.
 *     upgrade_main_savepoint(true, XXXXXXXXXX.XX);
 * }
 *
 * All plugins within Moodle (modules, blocks, reports...) support the existence of
 * their own upgrade.php file, using the "Frankenstyle" component name as
 * defined at {@link http://docs.moodle.org/dev/Frankenstyle}, for example:
 *     - {@link xmldb_page_upgrade($oldversion)}. (modules don't require the plugintype ("mod_") to be used.
 *     - {@link xmldb_auth_manual_upgrade($oldversion)}.
 *     - {@link xmldb_workshopform_accumulative_upgrade($oldversion)}.
 *     - ....
 *
 * In order to keep the contents of this file reduced, it's allowed to create some helper
 * functions to be used here in the {@link upgradelib.php} file at the same directory. Note
 * that such a file must be manually included from upgrade.php, and there are some restrictions
 * about what can be used within it.
 *
 * For more information, take a look to the documentation available:
 *     - Data definition API: {@link http://docs.moodle.org/dev/Data_definition_API}
 *     - Upgrade API: {@link http://docs.moodle.org/dev/Upgrade_API}
 *
 * @param int $oldversion
 * @return bool always true
 */
function xmldb_main_upgrade($oldversion)
{
    global $CFG, $USER, $DB, $OUTPUT, $SITE, $COURSE;
    require_once $CFG->libdir . '/db/upgradelib.php';
    // Core Upgrade-related functions
    $dbman = $DB->get_manager();
    // loads ddl manager and xmldb classes
    if ($oldversion < 2011120500) {
        // just in case somebody hacks upgrade scripts or env, we really can not continue
        echo "You need to upgrade to 2.2.x first!\n";
        exit(1);
        // Note this savepoint is 100% unreachable, but needed to pass the upgrade checks
        upgrade_main_savepoint(true, 2011120500);
    }
    // Moodle v2.2.0 release upgrade line
    // Put any upgrade step following this
    if ($oldversion < 2011120500.02) {
        upgrade_set_timeout(60 * 20);
        // This may take a while
        // MDL-28180. Some missing restrictions in certain backup & restore operations
        // were causing incorrect duplicates in the course_completion_aggr_methd table.
        // This upgrade step takes rid of them.
        $sql = 'SELECT course, criteriatype, MIN(id) AS minid
                  FROM {course_completion_aggr_methd}
              GROUP BY course, criteriatype
                HAVING COUNT(*) > 1';
        $duprs = $DB->get_recordset_sql($sql);
        foreach ($duprs as $duprec) {
            // We need to handle NULLs in criteriatype diferently
            if (is_null($duprec->criteriatype)) {
                $where = 'course = ? AND criteriatype IS NULL AND id > ?';
                $params = array($duprec->course, $duprec->minid);
            } else {
                $where = 'course = ? AND criteriatype = ? AND id > ?';
                $params = array($duprec->course, $duprec->criteriatype, $duprec->minid);
            }
            $DB->delete_records_select('course_completion_aggr_methd', $where, $params);
        }
        $duprs->close();
        // Main savepoint reached
        upgrade_main_savepoint(true, 2011120500.02);
    }
    if ($oldversion < 2011120500.03) {
        // Changing precision of field value on table user_preferences to (1333)
        $table = new xmldb_table('user_preferences');
        $field = new xmldb_field('value', XMLDB_TYPE_CHAR, '1333', null, XMLDB_NOTNULL, null, null, 'name');
        // Launch change of precision for field value
        $dbman->change_field_precision($table, $field);
        // Main savepoint reached
        upgrade_main_savepoint(true, 2011120500.03);
    }
    if ($oldversion < 2012020200.03) {
        // Define index rolecontext (not unique) to be added to role_assignments
        $table = new xmldb_table('role_assignments');
        $index = new xmldb_index('rolecontext', XMLDB_INDEX_NOTUNIQUE, array('roleid', 'contextid'));
        // Conditionally launch add index rolecontext
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Define index usercontextrole (not unique) to be added to role_assignments
        $index = new xmldb_index('usercontextrole', XMLDB_INDEX_NOTUNIQUE, array('userid', 'contextid', 'roleid'));
        // Conditionally launch add index usercontextrole
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012020200.03);
    }
    if ($oldversion < 2012020200.06) {
        // Previously we always allowed users to override their email address via the messaging system
        // We have now added a setting to allow admins to turn this this ability on and off
        // While this setting defaults to 0 (off) we're setting it to 1 (on) to maintain the behaviour for upgrading sites
        set_config('messagingallowemailoverride', 1);
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012020200.06);
    }
    if ($oldversion < 2012021700.01) {
        // Changing precision of field uniquehash on table post to 255
        $table = new xmldb_table('post');
        $field = new xmldb_field('uniquehash', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'content');
        // Launch change of precision for field uniquehash
        $dbman->change_field_precision($table, $field);
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012021700.01);
    }
    if ($oldversion < 2012021700.02) {
        // Somewhere before 1.9 summary and content column in post table were not null. In 1.9+
        // not null became false.
        $columns = $DB->get_columns('post');
        // Fix discrepancies in summary field after upgrade from 1.9
        if (array_key_exists('summary', $columns) && $columns['summary']->not_null != false) {
            $table = new xmldb_table('post');
            $summaryfield = new xmldb_field('summary', XMLDB_TYPE_TEXT, 'big', null, null, null, null, 'subject');
            if ($dbman->field_exists($table, $summaryfield)) {
                $dbman->change_field_notnull($table, $summaryfield);
            }
        }
        // Fix discrepancies in content field after upgrade from 1.9
        if (array_key_exists('content', $columns) && $columns['content']->not_null != false) {
            $table = new xmldb_table('post');
            $contentfield = new xmldb_field('content', XMLDB_TYPE_TEXT, 'big', null, null, null, null, 'summary');
            if ($dbman->field_exists($table, $contentfield)) {
                $dbman->change_field_notnull($table, $contentfield);
            }
        }
        upgrade_main_savepoint(true, 2012021700.02);
    }
    // The ability to backup user (private) files is out completely - MDL-29248
    if ($oldversion < 2012030100.01) {
        unset_config('backup_general_user_files', 'backup');
        unset_config('backup_general_user_files_locked', 'backup');
        unset_config('backup_auto_user_files', 'backup');
        upgrade_main_savepoint(true, 2012030100.01);
    }
    if ($oldversion < 2012030900.01) {
        // Migrate all numbers to signed & all texts and binaries to big size.
        // It should be safe to interrupt this and continue later.
        upgrade_mysql_fix_unsigned_and_lob_columns();
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012030900.01);
    }
    if ($oldversion < 2012031500.01) {
        // Upgrade old course_allowed_modules data to be permission overrides.
        if ($CFG->restrictmodulesfor === 'all') {
            $courses = $DB->get_records_menu('course', array(), 'id', 'id, 1');
        } else {
            if ($CFG->restrictmodulesfor === 'requested') {
                $courses = $DB->get_records_menu('course', array('restrictmodules' => 1), 'id', 'id, 1');
            } else {
                $courses = array();
            }
        }
        if (!$dbman->table_exists('course_allowed_modules')) {
            // Upgrade must already have been run on this server. This might happen,
            // for example, during development of these changes.
            $courses = array();
        }
        $modidtoname = $DB->get_records_menu('modules', array(), 'id', 'id, name');
        $coursecount = count($courses);
        if ($coursecount) {
            $pbar = new progress_bar('allowedmods', 500, true);
            $transaction = $DB->start_delegated_transaction();
        }
        $i = 0;
        foreach ($courses as $courseid => $notused) {
            $i += 1;
            upgrade_set_timeout(60);
            // 1 minute per course should be fine.
            $allowedmoduleids = $DB->get_records_menu('course_allowed_modules', array('course' => $courseid), 'module', 'module, 1');
            if (empty($allowedmoduleids)) {
                // This seems to be the best match for backwards compatibility,
                // not necessarily with the old code in course_allowed_module function,
                // but with the code that used to be in the coures settings form.
                $allowedmoduleids = explode(',', $CFG->defaultallowedmodules);
                $allowedmoduleids = array_combine($allowedmoduleids, $allowedmoduleids);
            }
            $context = context_course::instance($courseid);
            list($roleids) = get_roles_with_cap_in_context($context, 'moodle/course:manageactivities');
            list($managerroleids) = get_roles_with_cap_in_context($context, 'moodle/site:config');
            foreach ($managerroleids as $roleid) {
                unset($roleids[$roleid]);
            }
            foreach ($modidtoname as $modid => $modname) {
                if (isset($allowedmoduleids[$modid])) {
                    // Module is allowed, no worries.
                    continue;
                }
                $capability = 'mod/' . $modname . ':addinstance';
                foreach ($roleids as $roleid) {
                    assign_capability($capability, CAP_PREVENT, $roleid, $context);
                }
            }
            $pbar->update($i, $coursecount, "Upgrading legacy course_allowed_modules data - {$i}/{$coursecount}.");
        }
        if ($coursecount) {
            $transaction->allow_commit();
        }
        upgrade_main_savepoint(true, 2012031500.01);
    }
    if ($oldversion < 2012031500.02) {
        // Define field restrictmodules to be dropped from course
        $table = new xmldb_table('course');
        $field = new xmldb_field('restrictmodules');
        // Conditionally launch drop field requested
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Since structure of 'course' table has changed we need to re-read $SITE from DB.
        $SITE = $DB->get_record('course', array('id' => $SITE->id));
        $COURSE = clone $SITE;
        upgrade_main_savepoint(true, 2012031500.02);
    }
    if ($oldversion < 2012031500.03) {
        // Define table course_allowed_modules to be dropped
        $table = new xmldb_table('course_allowed_modules');
        // Conditionally launch drop table for course_allowed_modules
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        upgrade_main_savepoint(true, 2012031500.03);
    }
    if ($oldversion < 2012031500.04) {
        // Clean up the old admin settings.
        unset_config('restrictmodulesfor');
        unset_config('restrictbydefault');
        unset_config('defaultallowedmodules');
        upgrade_main_savepoint(true, 2012031500.04);
    }
    if ($oldversion < 2012032300.02) {
        // Migrate the old admin debug setting.
        if ($CFG->debug == 38911) {
            set_config('debug', DEBUG_DEVELOPER);
        } else {
            if ($CFG->debug == 6143) {
                set_config('debug', DEBUG_ALL);
            }
        }
        upgrade_main_savepoint(true, 2012032300.02);
    }
    if ($oldversion < 2012042300.0) {
        // This change makes the course_section index unique.
        // Look for any duplicate course_sections entries. There should not be
        // any but on some busy systems we found a few, maybe due to previous
        // bugs.
        $transaction = $DB->start_delegated_transaction();
        $rs = $DB->get_recordset_sql('
                SELECT DISTINCT
                    cs.id, cs.course
                FROM
                    {course_sections} cs
                    INNER JOIN {course_sections} older
                        ON cs.course = older.course AND cs.section = older.section
                        AND older.id < cs.id');
        foreach ($rs as $rec) {
            $DB->delete_records('course_sections', array('id' => $rec->id));
            // We can't use rebuild_course_cache() here because introducing sectioncache later
            // so reset modinfo manually.
            $DB->set_field('course', 'modinfo', null, array('id' => $rec->course));
        }
        $rs->close();
        $transaction->allow_commit();
        // XMLDB does not allow changing index uniqueness - instead we must drop
        // index then add it again.
        // MDL-46182: The query to make the index unique uses the index,
        // so the removal of the non-unique version needs to happen after any
        // data changes have been made.
        $table = new xmldb_table('course_sections');
        $index = new xmldb_index('course_section', XMLDB_INDEX_NOTUNIQUE, array('course', 'section'));
        // Conditionally launch drop index course_section.
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        // Define index course_section (unique) to be added to course_sections
        $index = new xmldb_index('course_section', XMLDB_INDEX_UNIQUE, array('course', 'section'));
        // Conditionally launch add index course_section
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012042300.0);
    }
    if ($oldversion < 2012042300.02) {
        require_once $CFG->dirroot . '/completion/criteria/completion_criteria.php';
        // Delete orphaned criteria which were left when modules were removed
        if ($DB->get_dbfamily() === 'mysql') {
            $sql = "DELETE cc FROM {course_completion_criteria} cc\n                    LEFT JOIN {course_modules} cm ON cm.id = cc.moduleinstance\n                    WHERE cm.id IS NULL AND cc.criteriatype = " . COMPLETION_CRITERIA_TYPE_ACTIVITY;
        } else {
            $sql = "DELETE FROM {course_completion_criteria}\n                    WHERE NOT EXISTS (\n                        SELECT 'x' FROM {course_modules}\n                        WHERE {course_modules}.id = {course_completion_criteria}.moduleinstance)\n                    AND {course_completion_criteria}.criteriatype = " . COMPLETION_CRITERIA_TYPE_ACTIVITY;
        }
        $DB->execute($sql);
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012042300.02);
    }
    if ($oldversion < 2012050300.01) {
        // Make sure deleted users do not have picture flag.
        $DB->set_field('user', 'picture', 0, array('deleted' => 1, 'picture' => 1));
        upgrade_main_savepoint(true, 2012050300.01);
    }
    if ($oldversion < 2012050300.02) {
        // Changing precision of field picture on table user to (10)
        $table = new xmldb_table('user');
        $field = new xmldb_field('picture', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'secret');
        // Launch change of precision for field picture
        $dbman->change_field_precision($table, $field);
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012050300.02);
    }
    if ($oldversion < 2012050300.03) {
        // Define field coursedisplay to be added to course
        $table = new xmldb_table('course');
        $field = new xmldb_field('coursedisplay', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'completionnotify');
        // Conditionally launch add field coursedisplay
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Since structure of 'course' table has changed we need to re-read $SITE from DB.
        $SITE = $DB->get_record('course', array('id' => $SITE->id));
        $COURSE = clone $SITE;
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012050300.03);
    }
    if ($oldversion < 2012050300.04) {
        // Define table course_display to be dropped
        $table = new xmldb_table('course_display');
        // Conditionally launch drop table for course_display
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012050300.04);
    }
    if ($oldversion < 2012050300.05) {
        // Clean up removed admin setting.
        unset_config('navlinkcoursesections');
        upgrade_main_savepoint(true, 2012050300.05);
    }
    if ($oldversion < 2012050400.01) {
        // Define index sortorder (not unique) to be added to course
        $table = new xmldb_table('course');
        $index = new xmldb_index('sortorder', XMLDB_INDEX_NOTUNIQUE, array('sortorder'));
        // Conditionally launch add index sortorder
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012050400.01);
    }
    if ($oldversion < 2012050400.02) {
        // Clean up removed admin setting.
        unset_config('enablecourseajax');
        upgrade_main_savepoint(true, 2012050400.02);
    }
    if ($oldversion < 2012051100.01) {
        // Define field idnumber to be added to groups
        $table = new xmldb_table('groups');
        $field = new xmldb_field('idnumber', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'courseid');
        $index = new xmldb_index('idnumber', XMLDB_INDEX_NOTUNIQUE, array('idnumber'));
        // Conditionally launch add field idnumber
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Conditionally launch add index idnumber
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Define field idnumber to be added to groupings
        $table = new xmldb_table('groupings');
        $field = new xmldb_field('idnumber', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'name');
        $index = new xmldb_index('idnumber', XMLDB_INDEX_NOTUNIQUE, array('idnumber'));
        // Conditionally launch add field idnumber
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Conditionally launch add index idnumber
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012051100.01);
    }
    if ($oldversion < 2012051100.03) {
        // Amend course table to add sectioncache cache
        $table = new xmldb_table('course');
        $field = new xmldb_field('sectioncache', XMLDB_TYPE_TEXT, null, null, null, null, null, 'showgrades');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Amend course_sections to add date, time and groupingid availability
        // conditions and a setting about whether to show them
        $table = new xmldb_table('course_sections');
        $field = new xmldb_field('availablefrom', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'visible');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('availableuntil', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'availablefrom');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('showavailability', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'availableuntil');
        // Conditionally launch add field showavailability
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('groupingid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'showavailability');
        // Conditionally launch add field groupingid
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Since structure of 'course' table has changed we need to re-read $SITE from DB.
        $SITE = $DB->get_record('course', array('id' => $SITE->id));
        $COURSE = clone $SITE;
        // Add course_sections_availability to add completion & grade availability conditions
        $table = new xmldb_table('course_sections_availability');
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('coursesectionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('sourcecmid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('requiredcompletion', XMLDB_TYPE_INTEGER, '1', null, null, null, null);
        $table->add_field('gradeitemid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('grademin', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null);
        $table->add_field('grademax', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null);
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('coursesectionid', XMLDB_KEY_FOREIGN, array('coursesectionid'), 'course_sections', array('id'));
        $table->add_key('sourcecmid', XMLDB_KEY_FOREIGN, array('sourcecmid'), 'course_modules', array('id'));
        $table->add_key('gradeitemid', XMLDB_KEY_FOREIGN, array('gradeitemid'), 'grade_items', array('id'));
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012051100.03);
    }
    if ($oldversion < 2012052100.0) {
        // Define field referencefileid to be added to files.
        $table = new xmldb_table('files');
        // Define field referencefileid to be added to files.
        $field = new xmldb_field('referencefileid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'sortorder');
        // Conditionally launch add field referencefileid.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field referencelastsync to be added to files.
        $field = new xmldb_field('referencelastsync', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'referencefileid');
        // Conditionally launch add field referencelastsync.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field referencelifetime to be added to files.
        $field = new xmldb_field('referencelifetime', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'referencelastsync');
        // Conditionally launch add field referencelifetime.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $key = new xmldb_key('referencefileid', XMLDB_KEY_FOREIGN, array('referencefileid'), 'files_reference', array('id'));
        // Launch add key referencefileid
        $dbman->add_key($table, $key);
        // Define table files_reference to be created.
        $table = new xmldb_table('files_reference');
        // Adding fields to table files_reference.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('repositoryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('lastsync', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('lifetime', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('reference', XMLDB_TYPE_TEXT, null, null, null, null, null);
        // Adding keys to table files_reference.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('repositoryid', XMLDB_KEY_FOREIGN, array('repositoryid'), 'repository_instances', array('id'));
        // Conditionally launch create table for files_reference
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012052100.0);
    }
    if ($oldversion < 2012052500.03) {
        // fix invalid course_completion_records MDL-27368
        //first get all instances of duplicate records
        $sql = 'SELECT userid, course FROM {course_completions} WHERE (deleted IS NULL OR deleted <> 1) GROUP BY userid, course HAVING (count(id) > 1)';
        $duplicates = $DB->get_recordset_sql($sql, array());
        foreach ($duplicates as $duplicate) {
            $pointer = 0;
            //now get all the records for this user/course
            $sql = 'userid = ? AND course = ? AND (deleted IS NULL OR deleted <> 1)';
            $completions = $DB->get_records_select('course_completions', $sql, array($duplicate->userid, $duplicate->course), 'timecompleted DESC, timestarted DESC');
            $needsupdate = false;
            $origcompletion = null;
            foreach ($completions as $completion) {
                $pointer++;
                if ($pointer === 1) {
                    //keep 1st record but delete all others.
                    $origcompletion = $completion;
                } else {
                    //we need to keep the "oldest" of all these fields as the valid completion record.
                    $fieldstocheck = array('timecompleted', 'timestarted', 'timeenrolled');
                    foreach ($fieldstocheck as $f) {
                        if ($origcompletion->{$f} > $completion->{$f}) {
                            $origcompletion->{$f} = $completion->{$f};
                            $needsupdate = true;
                        }
                    }
                    $DB->delete_records('course_completions', array('id' => $completion->id));
                }
            }
            if ($needsupdate) {
                $DB->update_record('course_completions', $origcompletion);
            }
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012052500.03);
    }
    if ($oldversion < 2012052900.0) {
        // Clean up all duplicate records in the course_completions table in preparation
        // for adding a new index there.
        upgrade_course_completion_remove_duplicates('course_completions', array('userid', 'course'), array('timecompleted', 'timestarted', 'timeenrolled'));
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012052900.0);
    }
    if ($oldversion < 2012052900.01) {
        // Add indexes to prevent new duplicates in the course_completions table.
        // Define index useridcourse (unique) to be added to course_completions
        $table = new xmldb_table('course_completions');
        $index = new xmldb_index('useridcourse', XMLDB_INDEX_UNIQUE, array('userid', 'course'));
        // Conditionally launch add index useridcourse
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012052900.01);
    }
    if ($oldversion < 2012052900.02) {
        // Clean up all duplicate records in the course_completion_crit_compl table in preparation
        // for adding a new index there.
        upgrade_course_completion_remove_duplicates('course_completion_crit_compl', array('userid', 'course', 'criteriaid'), array('timecompleted'));
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012052900.02);
    }
    if ($oldversion < 2012052900.03) {
        // Add indexes to prevent new duplicates in the course_completion_crit_compl table.
        // Define index useridcoursecriteraid (unique) to be added to course_completion_crit_compl
        $table = new xmldb_table('course_completion_crit_compl');
        $index = new xmldb_index('useridcoursecriteraid', XMLDB_INDEX_UNIQUE, array('userid', 'course', 'criteriaid'));
        // Conditionally launch add index useridcoursecriteraid
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012052900.03);
    }
    if ($oldversion < 2012052900.04) {
        // Clean up all duplicate records in the course_completion_aggr_methd table in preparation
        // for adding a new index there.
        upgrade_course_completion_remove_duplicates('course_completion_aggr_methd', array('course', 'criteriatype'));
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012052900.04);
    }
    if ($oldversion < 2012052900.05) {
        // Add indexes to prevent new duplicates in the course_completion_aggr_methd table.
        // Define index coursecriteratype (unique) to be added to course_completion_aggr_methd
        $table = new xmldb_table('course_completion_aggr_methd');
        $index = new xmldb_index('coursecriteriatype', XMLDB_INDEX_UNIQUE, array('course', 'criteriatype'));
        // Conditionally launch add index coursecriteratype
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012052900.05);
    }
    if ($oldversion < 2012060600.01) {
        // Add field referencehash to files_reference
        $table = new xmldb_table('files_reference');
        $field = new xmldb_field('referencehash', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null, 'reference');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        upgrade_main_savepoint(true, 2012060600.01);
    }
    if ($oldversion < 2012060600.02) {
        // Populate referencehash field with SHA1 hash of the reference - this shoudl affect only 2.3dev sites
        // that were using the feature for testing. Production sites have the table empty.
        $rs = $DB->get_recordset('files_reference', null, '', 'id, reference');
        foreach ($rs as $record) {
            $hash = sha1($record->reference);
            $DB->set_field('files_reference', 'referencehash', $hash, array('id' => $record->id));
        }
        $rs->close();
        upgrade_main_savepoint(true, 2012060600.02);
    }
    if ($oldversion < 2012060600.03) {
        // Merge duplicate records in files_reference that were created during the development
        // phase at 2.3dev sites. This is needed so we can create the unique index over
        // (repositoryid, referencehash) fields.
        $sql = "SELECT repositoryid, referencehash, MIN(id) AS minid\n                  FROM {files_reference}\n              GROUP BY repositoryid, referencehash\n                HAVING COUNT(*) > 1";
        $duprs = $DB->get_recordset_sql($sql);
        foreach ($duprs as $duprec) {
            // get the list of all ids in {files_reference} that need to be remapped
            $dupids = $DB->get_records_select('files_reference', "repositoryid = ? AND referencehash = ? AND id > ?", array($duprec->repositoryid, $duprec->referencehash, $duprec->minid), '', 'id');
            $dupids = array_keys($dupids);
            // relink records in {files} that are now referring to a duplicate record
            // in {files_reference} to refer to the first one
            list($subsql, $subparams) = $DB->get_in_or_equal($dupids);
            $DB->set_field_select('files', 'referencefileid', $duprec->minid, "referencefileid {$subsql}", $subparams);
            // and finally remove all orphaned records from {files_reference}
            $DB->delete_records_list('files_reference', 'id', $dupids);
        }
        $duprs->close();
        upgrade_main_savepoint(true, 2012060600.03);
    }
    if ($oldversion < 2012060600.04) {
        // Add a unique index over repositoryid and referencehash fields in files_reference table
        $table = new xmldb_table('files_reference');
        $index = new xmldb_index('uq_external_file', XMLDB_INDEX_UNIQUE, array('repositoryid', 'referencehash'));
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        upgrade_main_savepoint(true, 2012060600.04);
    }
    if ($oldversion < 2012061800.01) {
        // Define field screenreader to be dropped from user
        $table = new xmldb_table('user');
        $field = new xmldb_field('ajax');
        // Conditionally launch drop field screenreader
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012061800.01);
    }
    if ($oldversion < 2012062000.0) {
        // Add field newcontextid to backup_files_template
        $table = new xmldb_table('backup_files_template');
        $field = new xmldb_field('newcontextid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'info');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        upgrade_main_savepoint(true, 2012062000.0);
    }
    if ($oldversion < 2012062000.01) {
        // Add field newitemid to backup_files_template
        $table = new xmldb_table('backup_files_template');
        $field = new xmldb_field('newitemid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'newcontextid');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        upgrade_main_savepoint(true, 2012062000.01);
    }
    // Moodle v2.3.0 release upgrade line
    // Put any upgrade step following this
    if ($oldversion < 2012062500.02) {
        // Drop some old backup tables, not used anymore
        // Define table backup_files to be dropped
        $table = new xmldb_table('backup_files');
        // Conditionally launch drop table for backup_files
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        // Define table backup_ids to be dropped
        $table = new xmldb_table('backup_ids');
        // Conditionally launch drop table for backup_ids
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012062500.02);
    }
    if ($oldversion < 2012070600.04) {
        // Define table course_modules_avail_fields to be created
        $table = new xmldb_table('course_modules_avail_fields');
        // Adding fields to table course_modules_avail_fields
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('coursemoduleid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('userfield', XMLDB_TYPE_CHAR, '50', null, null, null, null);
        $table->add_field('customfieldid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('operator', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null);
        $table->add_field('value', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table course_modules_avail_fields
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('coursemoduleid', XMLDB_KEY_FOREIGN, array('coursemoduleid'), 'course_modules', array('id'));
        // Conditionally launch create table for course_modules_avail_fields
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012070600.04);
    }
    if ($oldversion < 2012070600.05) {
        // Define table course_sections_avail_fields to be created
        $table = new xmldb_table('course_sections_avail_fields');
        // Adding fields to table course_sections_avail_fields
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('coursesectionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('userfield', XMLDB_TYPE_CHAR, '50', null, null, null, null);
        $table->add_field('customfieldid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('operator', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null);
        $table->add_field('value', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table course_sections_avail_fields
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('coursesectionid', XMLDB_KEY_FOREIGN, array('coursesectionid'), 'course_sections', array('id'));
        // Conditionally launch create table for course_sections_avail_fields
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012070600.05);
    }
    if ($oldversion < 2012070600.06) {
        // Drop "deleted" fields
        $table = new xmldb_table('course_completions');
        $field = new xmldb_field('timenotified');
        $field = new xmldb_field('deleted');
        // Conditionally launch drop field deleted from course_completions
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        $field = new xmldb_field('timenotified');
        // Conditionally launch drop field timenotified from course_completions
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012070600.06);
    }
    if ($oldversion < 2012070600.07) {
        $table = new xmldb_table('course_completion_crit_compl');
        $field = new xmldb_field('deleted');
        // Conditionally launch drop field deleted from course_completion_crit_compl
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012070600.07);
    }
    if ($oldversion < 2012070600.08) {
        // Drop unused table "course_completion_notify"
        $table = new xmldb_table('course_completion_notify');
        // Conditionally launch drop table course_completion_notify
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012070600.08);
    }
    if ($oldversion < 2012070600.09) {
        // Define index path (not unique) to be added to context
        $table = new xmldb_table('context');
        $index = new xmldb_index('path', XMLDB_INDEX_NOTUNIQUE, array('path'), array('varchar_pattern_ops'));
        // Recreate index with new pattern hint
        if ($DB->get_dbfamily() === 'postgres') {
            if ($dbman->index_exists($table, $index)) {
                $dbman->drop_index($table, $index);
            }
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012070600.09);
    }
    if ($oldversion < 2012070600.1) {
        // Define index name (unique) to be dropped form role
        $table = new xmldb_table('role');
        $index = new xmldb_index('name', XMLDB_INDEX_UNIQUE, array('name'));
        // Conditionally launch drop index name
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012070600.1);
    }
    if ($oldversion < 2012070600.11) {
        // Define index component-itemid-userid (not unique) to be added to role_assignments
        $table = new xmldb_table('role_assignments');
        $index = new xmldb_index('component-itemid-userid', XMLDB_INDEX_NOTUNIQUE, array('component', 'itemid', 'userid'));
        // Conditionally launch add index component-itemid-userid
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012070600.11);
    }
    if ($oldversion < 2012071900.01) {
        // Cleanup after simpeltests tool
        capabilities_cleanup('tool_unittest');
        unset_all_config_for_plugin('tool_unittest');
        upgrade_main_savepoint(true, 2012071900.01);
    }
    if ($oldversion < 2012072400.0) {
        // Remove obsolete xhtml strict setting - use THEME->doctype in theme config if necessary,
        // see theme_config->doctype in lib/outputlib.php for more details.
        unset_config('xmlstrictheaders');
        upgrade_main_savepoint(true, 2012072400.0);
    }
    if ($oldversion < 2012072401.0) {
        // Saves orphaned questions from the Dark Side
        upgrade_save_orphaned_questions();
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012072401.0);
    }
    if ($oldversion < 2012072600.01) {
        // Handle events with empty eventtype //MDL-32827
        $DB->set_field('event', 'eventtype', 'site', array('eventtype' => '', 'courseid' => $SITE->id));
        $DB->set_field_select('event', 'eventtype', 'due', "eventtype = '' AND courseid != 0 AND groupid = 0 AND (modulename = 'assignment' OR modulename = 'assign')");
        $DB->set_field_select('event', 'eventtype', 'course', "eventtype = '' AND courseid != 0 AND groupid = 0");
        $DB->set_field_select('event', 'eventtype', 'group', "eventtype = '' AND groupid != 0");
        $DB->set_field_select('event', 'eventtype', 'user', "eventtype = '' AND userid != 0");
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012072600.01);
    }
    if ($oldversion < 2012080200.02) {
        // Drop obsolete question upgrade field that should have been added to the install.xml.
        $table = new xmldb_table('question');
        $field = new xmldb_field('oldquestiontextformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        upgrade_main_savepoint(true, 2012080200.02);
    }
    if ($oldversion < 2012081400.01) {
        // Move the ability to disable blogs to its own setting MDL-25012.
        if (isset($CFG->bloglevel)) {
            // Only change settings if existing setting was set.
            if (empty($CFG->bloglevel)) {
                set_config('enableblogs', 0);
                // Now set the bloglevel to a valid setting as the disabled setting has been removed.
                // This prevents confusing results when users enable the blog system in future.
                set_config('bloglevel', BLOG_USER_LEVEL);
            } else {
                set_config('enableblogs', 1);
            }
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012081400.01);
    }
    if ($oldversion < 2012081600.01) {
        // Delete removed setting - Google Maps API V2 will not work in 2013.
        unset_config('googlemapkey');
        upgrade_main_savepoint(true, 2012081600.01);
    }
    if ($oldversion < 2012082300.01) {
        // Add more custom enrol fields.
        $table = new xmldb_table('enrol');
        $field = new xmldb_field('customint5', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'customint4');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('customint6', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'customint5');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('customint7', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'customint6');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('customint8', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'customint7');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('customchar3', XMLDB_TYPE_CHAR, '1333', null, null, null, null, 'customchar2');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('customtext3', XMLDB_TYPE_TEXT, null, null, null, null, null, 'customtext2');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('customtext4', XMLDB_TYPE_TEXT, null, null, null, null, null, 'customtext3');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012082300.01);
    }
    if ($oldversion < 2012082300.02) {
        // Define field component to be added to groups_members
        $table = new xmldb_table('groups_members');
        $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'timeadded');
        // Conditionally launch add field component
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field itemid to be added to groups_members
        $field = new xmldb_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'component');
        // Conditionally launch add field itemid
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012082300.02);
    }
    if ($oldversion < 2012090500.0) {
        $subquery = 'SELECT b.id FROM {blog_external} b where b.id = ' . $DB->sql_cast_char2int('{post}.content', true);
        $sql = 'DELETE FROM {post}
                      WHERE {post}.module = \'blog_external\'
                            AND NOT EXISTS (' . $subquery . ')
                            AND ' . $DB->sql_isnotempty('post', 'uniquehash', false, false);
        $DB->execute($sql);
        upgrade_main_savepoint(true, 2012090500.0);
    }
    if ($oldversion < 2012090700.01) {
        // Add a category field in the course_request table
        $table = new xmldb_table('course_request');
        $field = new xmldb_field('category', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0, 'summaryformat');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012090700.01);
    }
    if ($oldversion < 2012091700.0) {
        // Dropping screenreader field from user.
        $table = new xmldb_table('user');
        $field = new xmldb_field('screenreader');
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012091700.0);
    }
    if ($oldversion < 2012092100.01) {
        // Some folders still have a sortorder set, which is used for main files but is not
        // supported by the folder resource. We reset the value here.
        $sql = 'UPDATE {files} SET sortorder = ? WHERE component = ? AND filearea = ? AND sortorder <> ?';
        $DB->execute($sql, array(0, 'mod_folder', 'content', 0));
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012092100.01);
    }
    if ($oldversion < 2012092600.0) {
        // Define index idname (unique) to be added to tag
        $table = new xmldb_table('tag');
        $index = new xmldb_index('idname', XMLDB_INDEX_UNIQUE, array('id', 'name'));
        // Conditionally launch add index idname
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012092600.0);
    }
    if ($oldversion < 2012101500.01) {
        // Find all orphaned blog associations that might exist.
        $sql = "SELECT ba.id\n                  FROM {blog_association} ba\n             LEFT JOIN {post} p\n                    ON p.id = ba.blogid\n                 WHERE p.id IS NULL";
        $orphanedrecordids = $DB->get_records_sql($sql);
        // Now delete these associations.
        foreach ($orphanedrecordids as $orphanedrecord) {
            $DB->delete_records('blog_association', array('id' => $orphanedrecord->id));
        }
        upgrade_main_savepoint(true, 2012101500.01);
    }
    if ($oldversion < 2012101800.02) {
        // Renaming backups using previous file naming convention.
        upgrade_rename_old_backup_files_using_shortname();
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012101800.02);
    }
    if ($oldversion < 2012103001.0) {
        // create new event_subscriptions table
        $table = new xmldb_table('event_subscriptions');
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('url', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('groupid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('pollinterval', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('lastupdated', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012103001.0);
    }
    if ($oldversion < 2012103002.0) {
        // Add subscription field to the event table
        $table = new xmldb_table('event');
        $field = new xmldb_field('subscriptionid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'timemodified');
        // Conditionally launch add field subscriptionid
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        upgrade_main_savepoint(true, 2012103002.0);
    }
    if ($oldversion < 2012103003.0) {
        // Fix uuid field in event table to match RFC-2445 UID property.
        $table = new xmldb_table('event');
        $field = new xmldb_field('uuid', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'visible');
        // The column already exists, so make sure there are no nulls (crazy mysql).
        $DB->set_field_select('event', 'uuid', '', "uuid IS NULL");
        // Changing precision of field uuid on table event to (255).
        $dbman->change_field_precision($table, $field);
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012103003.0);
    }
    if ($oldversion < 2012110200.0) {
        // Define table course_format_options to be created
        $table = new xmldb_table('course_format_options');
        // Adding fields to table course_format_options
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('format', XMLDB_TYPE_CHAR, '21', null, XMLDB_NOTNULL, null, null);
        $table->add_field('sectionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'format');
        $table->add_field('name', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
        $table->add_field('value', XMLDB_TYPE_TEXT, null, null, null, null, null);
        // Adding keys to table course_format_options
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('courseid', XMLDB_KEY_FOREIGN, array('courseid'), 'course', array('id'));
        // Adding indexes to table course_format_options
        $table->add_index('formatoption', XMLDB_INDEX_UNIQUE, array('courseid', 'format', 'sectionid', 'name'));
        // Conditionally launch create table for course_format_options
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Changing type of field format on table course to char with length 21
        $table = new xmldb_table('course');
        $field = new xmldb_field('format', XMLDB_TYPE_CHAR, '21', null, XMLDB_NOTNULL, null, 'topics', 'summaryformat');
        // Launch change of type for field format
        $dbman->change_field_type($table, $field);
        // Since structure of 'course' table has changed we need to re-read $SITE from DB.
        $SITE = $DB->get_record('course', array('id' => $SITE->id));
        $COURSE = clone $SITE;
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012110200.0);
    }
    if ($oldversion < 2012110201.0) {
        // Copy fields 'coursedisplay', 'numsections', 'hiddensections' from table {course}
        // to table {course_format_options} as the additional format options
        $fields = array();
        $table = new xmldb_table('course');
        foreach (array('coursedisplay', 'numsections', 'hiddensections') as $fieldname) {
            // first check that fields still exist
            $field = new xmldb_field($fieldname);
            if ($dbman->field_exists($table, $field)) {
                $fields[] = $fieldname;
            }
        }
        if (!empty($fields)) {
            $transaction = $DB->start_delegated_transaction();
            $rs = $DB->get_recordset_sql('SELECT id, format, ' . join(',', $fields) . '
                FROM {course}
                WHERE format <> ? AND format <> ?', array('scorm', 'social'));
            // (do not copy fields from scrom and social formats, we already know that they are not used)
            foreach ($rs as $rec) {
                foreach ($fields as $field) {
                    try {
                        $DB->insert_record('course_format_options', array('courseid' => $rec->id, 'format' => $rec->format, 'sectionid' => 0, 'name' => $field, 'value' => $rec->{$field}));
                    } catch (dml_exception $e) {
                        // index 'courseid,format,sectionid,name' violation
                        // continue; the entry in course_format_options already exists, use it
                    }
                }
            }
            $rs->close();
            $transaction->allow_commit();
            // Drop fields from table course
            foreach ($fields as $fieldname) {
                $field = new xmldb_field($fieldname);
                $dbman->drop_field($table, $field);
            }
        }
        // Since structure of 'course' table has changed we need to re-read $SITE from DB.
        $SITE = $DB->get_record('course', array('id' => $SITE->id));
        $COURSE = clone $SITE;
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012110201.0);
    }
    if ($oldversion < 2012110700.01) {
        // Define field caller_component to be added to portfolio_log.
        $table = new xmldb_table('portfolio_log');
        $field = new xmldb_field('caller_component', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'caller_file');
        // Conditionally launch add field caller_component.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012110700.01);
    }
    if ($oldversion < 2012111200.0) {
        // Define table temp_enroled_template to be created
        $table = new xmldb_table('temp_enroled_template');
        // Adding fields to table temp_enroled_template
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('roleid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table temp_enroled_template
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table temp_enroled_template
        $table->add_index('userid', XMLDB_INDEX_NOTUNIQUE, array('userid'));
        $table->add_index('courseid', XMLDB_INDEX_NOTUNIQUE, array('courseid'));
        $table->add_index('roleid', XMLDB_INDEX_NOTUNIQUE, array('roleid'));
        // Conditionally launch create table for temp_enroled_template
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table temp_log_template to be created
        $table = new xmldb_table('temp_log_template');
        // Adding fields to table temp_log_template
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('action', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table temp_log_template
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table temp_log_template
        $table->add_index('action', XMLDB_INDEX_NOTUNIQUE, array('action'));
        $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
        $table->add_index('user', XMLDB_INDEX_NOTUNIQUE, array('userid'));
        $table->add_index('usercourseaction', XMLDB_INDEX_NOTUNIQUE, array('userid', 'course', 'action'));
        // Conditionally launch create table for temp_log_template
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012111200.0);
    }
    if ($oldversion < 2012111200.01) {
        // Force the rebuild of the cache of every courses, some cached information could contain wrong icon references.
        $DB->execute('UPDATE {course} set modinfo = ?, sectioncache = ?', array(null, null));
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012111200.01);
    }
    if ($oldversion < 2012111601.01) {
        // Clea up after old shared memory caching support.
        unset_config('cachetype');
        unset_config('rcache');
        unset_config('rcachettl');
        unset_config('intcachemax');
        unset_config('memcachedhosts');
        unset_config('memcachedpconn');
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012111601.01);
    }
    if ($oldversion < 2012112100.0) {
        // Define field eventtype to be added to event_subscriptions.
        $table = new xmldb_table('event_subscriptions');
        $field = new xmldb_field('eventtype', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, 'userid');
        // Conditionally launch add field eventtype.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012112100.0);
    }
    // Moodle v2.4.0 release upgrade line
    // Put any upgrade step following this
    if ($oldversion < 2012120300.01) {
        // Make sure site-course has format='site' //MDL-36840
        if ($SITE->format !== 'site') {
            $DB->set_field('course', 'format', 'site', array('id' => $SITE->id));
            $SITE->format = 'site';
            $COURSE->format = 'site';
        }
        // Main savepoint reached
        upgrade_main_savepoint(true, 2012120300.01);
    }
    if ($oldversion < 2012120300.04) {
        // Remove "_utf8" suffix from all langs in course table.
        $langs = $DB->get_records_sql("SELECT DISTINCT lang FROM {course} WHERE lang LIKE ?", array('%_utf8'));
        foreach ($langs as $lang => $unused) {
            $newlang = str_replace('_utf8', '', $lang);
            $sql = "UPDATE {course} SET lang = :newlang WHERE lang = :lang";
            $DB->execute($sql, array('newlang' => $newlang, 'lang' => $lang));
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012120300.04);
    }
    if ($oldversion < 2012123000.0) {
        // Purge removed module filters and all their settings.
        $tables = array('filter_active', 'filter_config');
        foreach ($tables as $table) {
            $DB->delete_records_select($table, "filter LIKE 'mod/%'");
            $filters = $DB->get_records_sql("SELECT DISTINCT filter FROM {{$table}} WHERE filter LIKE 'filter/%'");
            foreach ($filters as $filter) {
                $DB->set_field($table, 'filter', substr($filter->filter, 7), array('filter' => $filter->filter));
            }
        }
        $configs = array('stringfilters', 'filterall');
        foreach ($configs as $config) {
            if ($filters = get_config(null, $config)) {
                $filters = explode(',', $filters);
                $newfilters = array();
                foreach ($filters as $filter) {
                    if (strpos($filter, '/') === false) {
                        $newfilters[] = $filter;
                    } else {
                        if (strpos($filter, 'filter/') === 0) {
                            $newfilters[] = substr($filter, 7);
                        }
                    }
                }
                $filters = implode(',', $newfilters);
                set_config($config, $filters);
            }
        }
        unset($tables);
        unset($table);
        unset($configs);
        unset($newfilters);
        unset($filters);
        unset($filter);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2012123000.0);
    }
    if ($oldversion < 2013021100.01) {
        // Make sure there are no bogus nulls in old MySQL tables.
        $DB->set_field_select('user', 'password', '', "password IS NULL");
        // Changing precision of field password on table user to (255).
        $table = new xmldb_table('user');
        $field = new xmldb_field('password', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'username');
        // Launch change of precision for field password.
        $dbman->change_field_precision($table, $field);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013021100.01);
    }
    if ($oldversion < 2013021800.0) {
        // Add the site identifier to the cache config's file.
        $siteidentifier = $DB->get_field('config', 'value', array('name' => 'siteidentifier'));
        cache_helper::update_site_identifier($siteidentifier);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013021800.0);
    }
    if ($oldversion < 2013021801.0) {
        // Fixing possible wrong MIME types for SMART Notebook files.
        $extensions = array('%.gallery', '%.galleryitem', '%.gallerycollection', '%.nbk', '%.notebook', '%.xbk');
        $select = $DB->sql_like('filename', '?', false);
        foreach ($extensions as $extension) {
            $DB->set_field_select('files', 'mimetype', 'application/x-smarttech-notebook', $select, array($extension));
        }
        upgrade_main_savepoint(true, 2013021801.0);
    }
    if ($oldversion < 2013021801.01) {
        // This upgrade step is re-written under MDL-38228 (see below).
        /*
        // Retrieve the list of course_sections as a recordset to save memory
        $coursesections = $DB->get_recordset('course_sections', null, 'course, id', 'id, course, sequence');
        foreach ($coursesections as $coursesection) {
            // Retrieve all of the actual modules in this course and section combination to reduce DB calls
            $actualsectionmodules = $DB->get_records('course_modules',
                    array('course' => $coursesection->course, 'section' => $coursesection->id), '', 'id, section');
        
            // Break out the current sequence so that we can compare it
            $currentsequence = explode(',', $coursesection->sequence);
            $newsequence = array();
        
            // Check each of the modules in the current sequence
            foreach ($currentsequence as $module) {
                if (isset($actualsectionmodules[$module])) {
                    $newsequence[] = $module;
                    // We unset the actualsectionmodules so that we don't get duplicates and that we can add orphaned
                    // modules later
                    unset($actualsectionmodules[$module]);
                }
            }
        
            // Append any modules which have somehow been orphaned
            foreach ($actualsectionmodules as $module) {
                $newsequence[] = $module->id;
            }
        
            // Piece it all back together
            $sequence = implode(',', $newsequence);
        
            // Only update if there have been changes
            if ($sequence !== $coursesection->sequence) {
                $coursesection->sequence = $sequence;
                $DB->update_record('course_sections', $coursesection);
        
                // And clear the sectioncache and modinfo cache - they'll be regenerated on next use
                $course = new stdClass();
                $course->id = $coursesection->course;
                $course->sectioncache = null;
                $course->modinfo = null;
                $DB->update_record('course', $course);
            }
        }
        $coursesections->close();
        */
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013021801.01);
    }
    if ($oldversion < 2013021902.0) {
        // ISO country change: Netherlands Antilles is split into BQ, CW & SX
        // http://www.iso.org/iso/iso_3166-1_newsletter_vi-8_split_of_the_dutch_antilles_final-en.pdf
        $sql = "UPDATE {user} SET country = '' WHERE country = ?";
        $DB->execute($sql, array('AN'));
        upgrade_main_savepoint(true, 2013021902.0);
    }
    if ($oldversion < 2013022600.0) {
        // Delete entries regarding invalid 'interests' option which breaks course.
        $DB->delete_records('course_sections_avail_fields', array('userfield' => 'interests'));
        $DB->delete_records('course_modules_avail_fields', array('userfield' => 'interests'));
        // Clear course cache (will be rebuilt on first visit) in case of changes to these.
        $DB->execute('UPDATE {course} set modinfo = ?, sectioncache = ?', array(null, null));
        upgrade_main_savepoint(true, 2013022600.0);
    }
    // Add index to field "timemodified" for grade_grades_history table.
    if ($oldversion < 2013030400.0) {
        $table = new xmldb_table('grade_grades_history');
        $field = new xmldb_field('timemodified');
        if ($dbman->field_exists($table, $field)) {
            $index = new xmldb_index('timemodified', XMLDB_INDEX_NOTUNIQUE, array('timemodified'));
            if (!$dbman->index_exists($table, $index)) {
                $dbman->add_index($table, $index);
            }
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013030400.0);
    }
    if ($oldversion < 2013030400.02) {
        // Cleanup qformat blackboard settings.
        unset_all_config_for_plugin('qformat_blackboard');
        upgrade_main_savepoint(true, 2013030400.02);
    }
    // This is checking to see if the site has been running a specific version with a bug in it
    // because this upgrade step is slow and is only needed if the site has been running with the affected versions.
    if ($oldversion >= 2012062504.08 && $oldversion < 2012062504.13) {
        // This upgrade step is re-written under MDL-38228 (see below).
        /*
                // Retrieve the list of course_sections as a recordset to save memory.
                // This is to fix a regression caused by MDL-37939.
                // In this case the upgrade step is fixing records where:
                // The data in course_sections.sequence contains the correct module id
                // The section field for on the course modules table may have been updated to point to the incorrect id.
        
                // This query is looking for sections where the sequence is not in sync with the course_modules table.
                // The syntax for the like query is looking for a value in a comma separated list.
                // It adds a comma to either site of the list and then searches for LIKE '%,id,%'.
                $sequenceconcat = $DB->sql_concat("','", 's.sequence', "','");
                $moduleconcat = $DB->sql_concat("'%,'", 'cm.id', "',%'");
                $sql = 'SELECT s2.id, s2.course, s2.sequence
               FROM {course_sections} s2
               JOIN(
                   SELECT DISTINCT s.id
                   FROM
                   {course_modules} cm
                   JOIN {course_sections} s
                   ON
                       cm.course = s.course
                   WHERE cm.section != s.id AND ' . $sequenceconcat . ' LIKE ' . $moduleconcat . '
               ) d
               ON s2.id = d.id';
                $coursesections = $DB->get_recordset_sql($sql);
        
                foreach ($coursesections as $coursesection) {
           // Retrieve all of the actual modules in this course and section combination to reduce DB calls.
           $actualsectionmodules = $DB->get_records('course_modules',
                   array('course' => $coursesection->course, 'section' => $coursesection->id), '', 'id, section');
        
           // Break out the current sequence so that we can compare it.
           $currentsequence = explode(',', $coursesection->sequence);
           $orphanlist = array();
        
           // Check each of the modules in the current sequence.
           foreach ($currentsequence as $cmid) {
               if (!empty($cmid) && !isset($actualsectionmodules[$cmid])) {
                   $orphanlist[] = $cmid;
               }
           }
        
           if (!empty($orphanlist)) {
               list($sql, $params) = $DB->get_in_or_equal($orphanlist, SQL_PARAMS_NAMED);
               $sql = "id $sql";
        
               $DB->set_field_select('course_modules', 'section', $coursesection->id, $sql, $params);
        
               // And clear the sectioncache and modinfo cache - they'll be regenerated on next use.
               $course = new stdClass();
               $course->id = $coursesection->course;
               $course->sectioncache = null;
               $course->modinfo = null;
               $DB->update_record('course', $course);
           }
                }
                $coursesections->close();
        
                // No savepoint needed for this change.
        */
    }
    if ($oldversion < 2013032200.01) {
        // GD is now always available
        set_config('gdversion', 2);
        upgrade_main_savepoint(true, 2013032200.01);
    }
    if ($oldversion < 2013032600.03) {
        // Fixing possible wrong MIME type for MIME HTML (MHTML) files.
        $extensions = array('%.mht', '%.mhtml');
        $select = $DB->sql_like('filename', '?', false);
        foreach ($extensions as $extension) {
            $DB->set_field_select('files', 'mimetype', 'message/rfc822', $select, array($extension));
        }
        upgrade_main_savepoint(true, 2013032600.03);
    }
    if ($oldversion < 2013032600.04) {
        // MDL-31983 broke the quiz version number. Fix it.
        $DB->set_field('modules', 'version', '2013021500', array('name' => 'quiz', 'version' => '2013310100'));
        upgrade_main_savepoint(true, 2013032600.04);
    }
    if ($oldversion < 2013040200.0) {
        // Add openbadges tables.
        // Define table 'badge' to be created.
        $table = new xmldb_table('badge');
        // Adding fields to table 'badge'.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'id');
        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null, 'name');
        $table->add_field('image', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'description');
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'image');
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'timecreated');
        $table->add_field('usercreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'timemodified');
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'usercreated');
        $table->add_field('issuername', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'usermodified');
        $table->add_field('issuerurl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'issuername');
        $table->add_field('issuercontact', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'issuerurl');
        $table->add_field('expiredate', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'issuercontact');
        $table->add_field('expireperiod', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'expiredate');
        $table->add_field('type', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'expireperiod');
        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'type');
        $table->add_field('message', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null, 'courseid');
        $table->add_field('messagesubject', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null, 'message');
        $table->add_field('attachment', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'messagesubject');
        $table->add_field('notification', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'attachment');
        $table->add_field('status', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'notification');
        $table->add_field('nextcron', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'status');
        // Adding keys to table 'badge'.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('fk_courseid', XMLDB_KEY_FOREIGN, array('courseid'), 'course', array('id'));
        $table->add_key('fk_usermodified', XMLDB_KEY_FOREIGN, array('usermodified'), 'user', array('id'));
        $table->add_key('fk_usercreated', XMLDB_KEY_FOREIGN, array('usercreated'), 'user', array('id'));
        // Adding indexes to table 'badge'.
        $table->add_index('type', XMLDB_INDEX_NOTUNIQUE, array('type'));
        // Conditionally launch create table for 'badge'.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table 'badge_criteria' to be created.
        $table = new xmldb_table('badge_criteria');
        // Adding fields to table 'badge_criteria'.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('badgeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'id');
        $table->add_field('criteriatype', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'badgeid');
        $table->add_field('method', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'criteriatype');
        // Adding keys to table 'badge_criteria'.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('fk_badgeid', XMLDB_KEY_FOREIGN, array('badgeid'), 'badge', array('id'));
        // Adding indexes to table 'badge_criteria'.
        $table->add_index('criteriatype', XMLDB_INDEX_NOTUNIQUE, array('criteriatype'));
        $table->add_index('badgecriteriatype', XMLDB_INDEX_UNIQUE, array('badgeid', 'criteriatype'));
        // Conditionally launch create table for 'badge_criteria'.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table 'badge_criteria_param' to be created.
        $table = new xmldb_table('badge_criteria_param');
        // Adding fields to table 'badge_criteria_param'.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('critid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'critid');
        $table->add_field('value', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'name');
        // Adding keys to table 'badge_criteria_param'.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('fk_critid', XMLDB_KEY_FOREIGN, array('critid'), 'badge_criteria', array('id'));
        // Conditionally launch create table for 'badge_criteria_param'.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table 'badge_issued' to be created.
        $table = new xmldb_table('badge_issued');
        // Adding fields to table 'badge_issued'.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('badgeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'id');
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'badgeid');
        $table->add_field('uniquehash', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null, 'userid');
        $table->add_field('dateissued', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'uniquehash');
        $table->add_field('dateexpire', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'dateissued');
        $table->add_field('visible', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'dateexpire');
        $table->add_field('issuernotified', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'visible');
        // Adding keys to table 'badge_issued'.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('fk_badgeid', XMLDB_KEY_FOREIGN, array('badgeid'), 'badge', array('id'));
        $table->add_key('fk_userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
        $table->add_index('badgeuser', XMLDB_INDEX_UNIQUE, array('badgeid', 'userid'));
        // Conditionally launch create table for 'badge_issued'.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table 'badge_criteria_met' to be created.
        $table = new xmldb_table('badge_criteria_met');
        // Adding fields to table 'badge_criteria_met'.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('issuedid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'id');
        $table->add_field('critid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'issuedid');
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'critid');
        $table->add_field('datemet', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid');
        // Adding keys to table 'badge_criteria_met'
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('fk_critid', XMLDB_KEY_FOREIGN, array('critid'), 'badge_criteria', array('id'));
        $table->add_key('fk_userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
        $table->add_key('fk_issuedid', XMLDB_KEY_FOREIGN, array('issuedid'), 'badge_issued', array('id'));
        // Conditionally launch create table for 'badge_criteria_met'.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table 'badge_manual_award' to be created.
        $table = new xmldb_table('badge_manual_award');
        // Adding fields to table 'badge_manual_award'.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('badgeid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
        $table->add_field('recipientid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'badgeid');
        $table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'recipientid');
        $table->add_field('issuerrole', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'issuerid');
        $table->add_field('datemet', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'issuerrole');
        // Adding keys to table 'badge_manual_award'.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('fk_badgeid', XMLDB_KEY_FOREIGN, array('badgeid'), 'badge', array('id'));
        $table->add_key('fk_recipientid', XMLDB_KEY_FOREIGN, array('recipientid'), 'user', array('id'));
        $table->add_key('fk_issuerid', XMLDB_KEY_FOREIGN, array('issuerid'), 'user', array('id'));
        $table->add_key('fk_issuerrole', XMLDB_KEY_FOREIGN, array('issuerrole'), 'role', array('id'));
        // Conditionally launch create table for 'badge_manual_award'.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table 'badge_backpack' to be created.
        $table = new xmldb_table('badge_backpack');
        // Adding fields to table 'badge_backpack'.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'id');
        $table->add_field('email', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'userid');
        $table->add_field('backpackurl', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'email');
        $table->add_field('backpackuid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'backpackurl');
        $table->add_field('backpackgid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'backpackuid');
        $table->add_field('autosync', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'backpackgid');
        $table->add_field('password', XMLDB_TYPE_CHAR, '50', null, null, null, null, 'autosync');
        // Adding keys to table 'badge_backpack'.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('fk_userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
        // Conditionally launch create table for 'badge_backpack'.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013040200.0);
    }
    if ($oldversion < 2013040201.0) {
        // Convert name field in event table to text type as RFC-2445 doesn't have any limitation on it.
        $table = new xmldb_table('event');
        $field = new xmldb_field('name', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
        if ($dbman->field_exists($table, $field)) {
            $dbman->change_field_type($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013040201.0);
    }
    if ($oldversion < 2013040300.01) {
        // Define field completionstartonenrol to be dropped from course.
        $table = new xmldb_table('course');
        $field = new xmldb_field('completionstartonenrol');
        // Conditionally launch drop field completionstartonenrol.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Since structure of 'course' table has changed we need to re-read $SITE from DB.
        $SITE = $DB->get_record('course', array('id' => $SITE->id));
        $COURSE = clone $SITE;
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013040300.01);
    }
    if ($oldversion < 2013041200.0) {
        // MDL-29877 Some bad restores created grade items with no category information.
        $sql = "UPDATE {grade_items}\n                   SET categoryid = courseid\n                 WHERE itemtype <> 'course' and itemtype <> 'category'\n                       AND categoryid IS NULL";
        $DB->execute($sql);
        upgrade_main_savepoint(true, 2013041200.0);
    }
    if ($oldversion < 2013041600.0) {
        // Copy constants from /course/lib.php instead of including the whole library:
        $c = array('FRONTPAGENEWS' => 0, 'FRONTPAGECOURSELIST' => 1, 'FRONTPAGECATEGORYNAMES' => 2, 'FRONTPAGETOPICONLY' => 3, 'FRONTPAGECATEGORYCOMBO' => 4, 'FRONTPAGEENROLLEDCOURSELIST' => 5, 'FRONTPAGEALLCOURSELIST' => 6, 'FRONTPAGECOURSESEARCH' => 7);
        // Update frontpage settings $CFG->frontpage and $CFG->frontpageloggedin. In 2.4 there was too much of hidden logic about them.
        // This script tries to make sure that with the new (more user-friendly) frontpage settings the frontpage looks as similar as possible to what it was before upgrade.
        $ncourses = $DB->count_records('course');
        foreach (array('frontpage', 'frontpageloggedin') as $configkey) {
            if ($frontpage = explode(',', $CFG->{$configkey})) {
                $newfrontpage = array();
                foreach ($frontpage as $v) {
                    switch ($v) {
                        case $c['FRONTPAGENEWS']:
                            // Not related to course listings, leave as it is.
                            $newfrontpage[] = $c['FRONTPAGENEWS'];
                            break;
                        case $c['FRONTPAGECOURSELIST']:
                            if ($configkey === 'frontpageloggedin' && empty($CFG->disablemycourses)) {
                                // In 2.4 unless prohibited in config, the "list of courses" was considered "list of enrolled courses" plus course search box.
                                $newfrontpage[] = $c['FRONTPAGEENROLLEDCOURSELIST'];
                            } else {
                                if ($ncourses <= 200) {
                                    // Still list of courses was only displayed in there were less than 200 courses in system. Otherwise - search box only.
                                    $newfrontpage[] = $c['FRONTPAGEALLCOURSELIST'];
                                    break;
                                    // skip adding search box
                                }
                            }
                            if (!in_array($c['FRONTPAGECOURSESEARCH'], $newfrontpage)) {
                                $newfrontpage[] = $c['FRONTPAGECOURSESEARCH'];
                            }
                            break;
                        case $c['FRONTPAGECATEGORYNAMES']:
                            // In 2.4 search box was displayed automatically after categories list. In 2.5 it is displayed as a separate setting.
                            $newfrontpage[] = $c['FRONTPAGECATEGORYNAMES'];
                            if (!in_array($c['FRONTPAGECOURSESEARCH'], $newfrontpage)) {
                                $newfrontpage[] = $c['FRONTPAGECOURSESEARCH'];
                            }
                            break;
                        case $c['FRONTPAGECATEGORYCOMBO']:
                            $maxcourses = empty($CFG->numcoursesincombo) ? 500 : $CFG->numcoursesincombo;
                            // In 2.4 combo list was not displayed if there are more than $CFG->numcoursesincombo courses in the system.
                            if ($ncourses < $maxcourses) {
                                $newfrontpage[] = $c['FRONTPAGECATEGORYCOMBO'];
                            }
                            if (!in_array($c['FRONTPAGECOURSESEARCH'], $newfrontpage)) {
                                $newfrontpage[] = $c['FRONTPAGECOURSESEARCH'];
                            }
                            break;
                    }
                }
                set_config($configkey, join(',', $newfrontpage));
            }
        }
        // $CFG->numcoursesincombo no longer affects whether the combo list is displayed. Setting is deprecated.
        unset_config('numcoursesincombo');
        upgrade_main_savepoint(true, 2013041600.0);
    }
    if ($oldversion < 2013041601.0) {
        // Create a new 'badge_external' table first.
        // Define table 'badge_external' to be created.
        $table = new xmldb_table('badge_external');
        // Adding fields to table 'badge_external'.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('backpackid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
        $table->add_field('collectionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'backpackid');
        // Adding keys to table 'badge_external'.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('fk_backpackid', XMLDB_KEY_FOREIGN, array('backpackid'), 'badge_backpack', array('id'));
        // Conditionally launch create table for 'badge_external'.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Perform user data migration.
        $usercollections = $DB->get_records('badge_backpack');
        foreach ($usercollections as $usercollection) {
            $collection = new stdClass();
            $collection->backpackid = $usercollection->id;
            $collection->collectionid = $usercollection->backpackgid;
            $DB->insert_record('badge_external', $collection);
        }
        // Finally, drop the column.
        // Define field backpackgid to be dropped from 'badge_backpack'.
        $table = new xmldb_table('badge_backpack');
        $field = new xmldb_field('backpackgid');
        // Conditionally launch drop field backpackgid.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013041601.0);
    }
    if ($oldversion < 2013041601.01) {
        // Changing the default of field descriptionformat on table user to 1.
        $table = new xmldb_table('user');
        $field = new xmldb_field('descriptionformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1', 'description');
        // Launch change of default for field descriptionformat.
        $dbman->change_field_default($table, $field);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013041601.01);
    }
    if ($oldversion < 2013041900.0) {
        require_once $CFG->dirroot . '/cache/locallib.php';
        // The features bin needs updating.
        cache_config_writer::update_default_config_stores();
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013041900.0);
    }
    if ($oldversion < 2013042300.0) {
        // Adding index to unreadmessageid field of message_working table (MDL-34933)
        $table = new xmldb_table('message_working');
        $index = new xmldb_index('unreadmessageid_idx', XMLDB_INDEX_NOTUNIQUE, array('unreadmessageid'));
        // Conditionally launch add index unreadmessageid
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013042300.0);
    }
    // Moodle v2.5.0 release upgrade line.
    // Put any upgrade step following this.
    if ($oldversion < 2013051400.01) {
        // Fix incorrect cc-nc url. Unfortunately the license 'plugins' do
        // not give a mechanism to do this.
        $sql = "UPDATE {license}\n                   SET source = :url, version = :newversion\n                 WHERE shortname = :shortname AND version = :oldversion";
        $params = array('url' => 'http://creativecommons.org/licenses/by-nc/3.0/', 'shortname' => 'cc-nc', 'newversion' => '2013051500', 'oldversion' => '2010033100');
        $DB->execute($sql, $params);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013051400.01);
    }
    if ($oldversion < 2013061400.01) {
        // Clean up old tokens which haven't been deleted.
        $DB->execute("DELETE FROM {user_private_key} WHERE NOT EXISTS\n                         (SELECT 'x' FROM {user} WHERE deleted = 0 AND id = userid)");
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013061400.01);
    }
    if ($oldversion < 2013061700.0) {
        // MDL-40103: Remove unused template tables from the database.
        // These are now created inline with xmldb_table.
        $tablestocleanup = array('temp_enroled_template', 'temp_log_template', 'backup_files_template', 'backup_ids_template');
        $dbman = $DB->get_manager();
        foreach ($tablestocleanup as $table) {
            $xmltable = new xmldb_table($table);
            if ($dbman->table_exists($xmltable)) {
                $dbman->drop_table($xmltable);
            }
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013061700.0);
    }
    if ($oldversion < 2013070800.0) {
        // Remove orphan repository instances.
        if ($DB->get_dbfamily() === 'mysql') {
            $sql = "DELETE {repository_instances} FROM {repository_instances}\n                    LEFT JOIN {context} ON {context}.id = {repository_instances}.contextid\n                    WHERE {context}.id IS NULL";
        } else {
            $sql = "DELETE FROM {repository_instances}\n                    WHERE NOT EXISTS (\n                        SELECT 'x' FROM {context}\n                        WHERE {context}.id = {repository_instances}.contextid)";
        }
        $DB->execute($sql);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013070800.0);
    }
    if ($oldversion < 2013070800.01) {
        // Define field lastnamephonetic to be added to user.
        $table = new xmldb_table('user');
        $field = new xmldb_field('lastnamephonetic', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'imagealt');
        $index = new xmldb_index('lastnamephonetic', XMLDB_INDEX_NOTUNIQUE, array('lastnamephonetic'));
        // Conditionally launch add field lastnamephonetic.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
            $dbman->add_index($table, $index);
        }
        // Define field firstnamephonetic to be added to user.
        $table = new xmldb_table('user');
        $field = new xmldb_field('firstnamephonetic', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'lastnamephonetic');
        $index = new xmldb_index('firstnamephonetic', XMLDB_INDEX_NOTUNIQUE, array('firstnamephonetic'));
        // Conditionally launch add field firstnamephonetic.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
            $dbman->add_index($table, $index);
        }
        // Define field alternatename to be added to user.
        $table = new xmldb_table('user');
        $field = new xmldb_field('middlename', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'firstnamephonetic');
        $index = new xmldb_index('middlename', XMLDB_INDEX_NOTUNIQUE, array('middlename'));
        // Conditionally launch add field firstnamephonetic.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
            $dbman->add_index($table, $index);
        }
        // Define field alternatename to be added to user.
        $table = new xmldb_table('user');
        $field = new xmldb_field('alternatename', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'middlename');
        $index = new xmldb_index('alternatename', XMLDB_INDEX_NOTUNIQUE, array('alternatename'));
        // Conditionally launch add field alternatename.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013070800.01);
    }
    if ($oldversion < 2013071500.01) {
        // The enrol_authorize plugin has been removed, if there are no records
        // and no plugin files then remove the plugin data.
        $enrolauthorize = new xmldb_table('enrol_authorize');
        $enrolauthorizerefunds = new xmldb_table('enrol_authorize_refunds');
        if (!file_exists($CFG->dirroot . '/enrol/authorize/version.php') && $dbman->table_exists($enrolauthorize) && $dbman->table_exists($enrolauthorizerefunds)) {
            $enrolauthorizecount = $DB->count_records('enrol_authorize');
            $enrolauthorizerefundcount = $DB->count_records('enrol_authorize_refunds');
            if (empty($enrolauthorizecount) && empty($enrolauthorizerefundcount)) {
                // Drop the database tables.
                $dbman->drop_table($enrolauthorize);
                $dbman->drop_table($enrolauthorizerefunds);
                // Drop the message provider and associated data manually.
                $DB->delete_records('message_providers', array('component' => 'enrol_authorize'));
                $DB->delete_records_select('config_plugins', "plugin = 'message' AND " . $DB->sql_like('name', '?', false), array("%_provider_enrol_authorize_%"));
                $DB->delete_records_select('user_preferences', $DB->sql_like('name', '?', false), array("message_provider_enrol_authorize_%"));
                // Remove capabilities.
                capabilities_cleanup('enrol_authorize');
                // Remove all other associated config.
                unset_all_config_for_plugin('enrol_authorize');
            }
        }
        upgrade_main_savepoint(true, 2013071500.01);
    }
    if ($oldversion < 2013071500.02) {
        // Define field attachment to be dropped from badge.
        $table = new xmldb_table('badge');
        $field = new xmldb_field('image');
        // Conditionally launch drop field eventtype.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        upgrade_main_savepoint(true, 2013071500.02);
    }
    if ($oldversion < 2013072600.01) {
        upgrade_mssql_nvarcharmax();
        upgrade_mssql_varbinarymax();
        upgrade_main_savepoint(true, 2013072600.01);
    }
    if ($oldversion < 2013081200.0) {
        // Define field uploadfiles to be added to external_services.
        $table = new xmldb_table('external_services');
        $field = new xmldb_field('uploadfiles', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'downloadfiles');
        // Conditionally launch add field uploadfiles.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013081200.0);
    }
    if ($oldversion < 2013082300.01) {
        // Define the table 'backup_logs' and the field 'message' which we will be changing from a char to a text field.
        $table = new xmldb_table('backup_logs');
        $field = new xmldb_field('message', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null, 'loglevel');
        // Perform the change.
        $dbman->change_field_type($table, $field);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013082300.01);
    }
    // Convert SCORM course format courses to singleactivity.
    if ($oldversion < 2013082700.0) {
        // First set relevant singleactivity settings.
        $formatoptions = new stdClass();
        $formatoptions->format = 'singleactivity';
        $formatoptions->sectionid = 0;
        $formatoptions->name = 'activitytype';
        $formatoptions->value = 'scorm';
        $courses = $DB->get_recordset('course', array('format' => 'scorm'), 'id');
        foreach ($courses as $course) {
            $formatoptions->courseid = $course->id;
            $DB->insert_record('course_format_options', $formatoptions);
        }
        $courses->close();
        // Now update course format for these courses.
        $sql = "UPDATE {course}\n                   SET format = 'singleactivity', modinfo = '', sectioncache = ''\n                 WHERE format = 'scorm'";
        $DB->execute($sql);
        upgrade_main_savepoint(true, 2013082700.0);
    }
    if ($oldversion < 2013090500.01) {
        // Define field calendartype to be added to course.
        $table = new xmldb_table('course');
        $field = new xmldb_field('calendartype', XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null);
        // Conditionally launch add field calendartype.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Since structure of 'course' table has changed we need to re-read $SITE from DB.
        $SITE = $DB->get_record('course', array('id' => $SITE->id));
        $COURSE = clone $SITE;
        // Define field calendartype to be added to user.
        $table = new xmldb_table('user');
        $field = new xmldb_field('calendartype', XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, 'gregorian');
        // Conditionally launch add field calendartype.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013090500.01);
    }
    if ($oldversion < 2013091000.02) {
        // Define field cacherev to be added to course.
        $table = new xmldb_table('course');
        $field = new xmldb_field('cacherev', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'completionnotify');
        // Conditionally launch add field cacherev.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Since structure of 'course' table has changed we need to re-read $SITE from DB.
        $SITE = $DB->get_record('course', array('id' => $SITE->id));
        $COURSE = clone $SITE;
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013091000.02);
    }
    if ($oldversion < 2013091000.03) {
        // Define field modinfo to be dropped from course.
        $table = new xmldb_table('course');
        $field = new xmldb_field('modinfo');
        // Conditionally launch drop field modinfo.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Define field sectioncache to be dropped from course.
        $field = new xmldb_field('sectioncache');
        // Conditionally launch drop field sectioncache.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Since structure of 'course' table has changed we need to re-read $SITE from DB.
        $SITE = $DB->get_record('course', array('id' => $SITE->id));
        $COURSE = clone $SITE;
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013091000.03);
    }
    if ($oldversion < 2013091300.01) {
        $table = new xmldb_table('user');
        // Changing precision of field institution on table user to (255).
        $field = new xmldb_field('institution', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'phone2');
        // Launch change of precision for field institution.
        $dbman->change_field_precision($table, $field);
        // Changing precision of field department on table user to (255).
        $field = new xmldb_field('department', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'institution');
        // Launch change of precision for field department.
        $dbman->change_field_precision($table, $field);
        // Changing precision of field address on table user to (255).
        $field = new xmldb_field('address', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'department');
        // Launch change of precision for field address.
        $dbman->change_field_precision($table, $field);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013091300.01);
    }
    if ($oldversion < 2013092000.01) {
        // Define table question_statistics to be created.
        $table = new xmldb_table('question_statistics');
        // Adding fields to table question_statistics.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('hashcode', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('questionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('slot', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('subquestion', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, null);
        $table->add_field('s', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('effectiveweight', XMLDB_TYPE_NUMBER, '15, 5', null, null, null, null);
        $table->add_field('negcovar', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('discriminationindex', XMLDB_TYPE_NUMBER, '15, 5', null, null, null, null);
        $table->add_field('discriminativeefficiency', XMLDB_TYPE_NUMBER, '15, 5', null, null, null, null);
        $table->add_field('sd', XMLDB_TYPE_NUMBER, '15, 10', null, null, null, null);
        $table->add_field('facility', XMLDB_TYPE_NUMBER, '15, 10', null, null, null, null);
        $table->add_field('subquestions', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('maxmark', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null);
        $table->add_field('positions', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('randomguessscore', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null);
        // Adding keys to table question_statistics.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Conditionally launch create table for question_statistics.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table question_response_analysis to be created.
        $table = new xmldb_table('question_response_analysis');
        // Adding fields to table question_response_analysis.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('hashcode', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('questionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('subqid', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
        $table->add_field('aid', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        $table->add_field('response', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('rcount', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('credit', XMLDB_TYPE_NUMBER, '15, 5', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table question_response_analysis.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Conditionally launch create table for question_response_analysis.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013092000.01);
    }
    if ($oldversion < 2013092001.01) {
        // Force uninstall of deleted tool.
        if (!file_exists("{$CFG->dirroot}/{$CFG->admin}/tool/bloglevelupgrade")) {
            // Remove capabilities.
            capabilities_cleanup('tool_bloglevelupgrade');
            // Remove all other associated config.
            unset_all_config_for_plugin('tool_bloglevelupgrade');
        }
        upgrade_main_savepoint(true, 2013092001.01);
    }
    if ($oldversion < 2013092001.02) {
        // Define field version to be dropped from modules.
        $table = new xmldb_table('modules');
        $field = new xmldb_field('version');
        // Conditionally launch drop field version.
        if ($dbman->field_exists($table, $field)) {
            // Migrate all plugin version info to config_plugins table.
            $modules = $DB->get_records('modules');
            foreach ($modules as $module) {
                set_config('version', $module->version, 'mod_' . $module->name);
            }
            unset($modules);
            $dbman->drop_field($table, $field);
        }
        // Define field version to be dropped from block.
        $table = new xmldb_table('block');
        $field = new xmldb_field('version');
        // Conditionally launch drop field version.
        if ($dbman->field_exists($table, $field)) {
            $blocks = $DB->get_records('block');
            foreach ($blocks as $block) {
                set_config('version', $block->version, 'block_' . $block->name);
            }
            unset($blocks);
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013092001.02);
    }
    if ($oldversion < 2013092700.01) {
        $table = new xmldb_table('files');
        // Define field referencelastsync to be dropped from files.
        $field = new xmldb_field('referencelastsync');
        // Conditionally launch drop field referencelastsync.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Define field referencelifetime to be dropped from files.
        $field = new xmldb_field('referencelifetime');
        // Conditionally launch drop field referencelifetime.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013092700.01);
    }
    if ($oldversion < 2013100400.01) {
        // Add user_devices core table.
        // Define field id to be added to user_devices.
        $table = new xmldb_table('user_devices');
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'id');
        $table->add_field('appid', XMLDB_TYPE_CHAR, '128', null, XMLDB_NOTNULL, null, null, 'userid');
        $table->add_field('name', XMLDB_TYPE_CHAR, '32', null, XMLDB_NOTNULL, null, null, 'appid');
        $table->add_field('model', XMLDB_TYPE_CHAR, '32', null, XMLDB_NOTNULL, null, null, 'name');
        $table->add_field('platform', XMLDB_TYPE_CHAR, '32', null, XMLDB_NOTNULL, null, null, 'model');
        $table->add_field('version', XMLDB_TYPE_CHAR, '32', null, XMLDB_NOTNULL, null, null, 'platform');
        $table->add_field('pushid', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'version');
        $table->add_field('uuid', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'pushid');
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'uuid');
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'timecreated');
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('pushid-userid', XMLDB_KEY_UNIQUE, array('pushid', 'userid'));
        $table->add_key('pushid-platform', XMLDB_KEY_UNIQUE, array('pushid', 'platform'));
        $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013100400.01);
    }
    if ($oldversion < 2013100800.0) {
        // Define field maxfraction to be added to question_attempts.
        $table = new xmldb_table('question_attempts');
        $field = new xmldb_field('maxfraction', XMLDB_TYPE_NUMBER, '12, 7', null, XMLDB_NOTNULL, null, '1', 'minfraction');
        // Conditionally launch add field maxfraction.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013100800.0);
    }
    if ($oldversion < 2013100800.01) {
        // Create a new 'user_password_resets' table.
        $table = new xmldb_table('user_password_resets');
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, null);
        $table->add_field('timerequested', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, null);
        $table->add_field('timererequested', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0, null);
        $table->add_field('token', XMLDB_TYPE_CHAR, '32', null, XMLDB_NOTNULL, null, null, null);
        // Adding keys to table.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('fk_userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
        // Conditionally launch create table.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        upgrade_main_savepoint(true, 2013100800.01);
    }
    if ($oldversion < 2013100800.02) {
        $sql = "INSERT INTO {user_preferences}(userid, name, value)\n                SELECT id, 'htmleditor', 'textarea' FROM {user} u where u.htmleditor = 0";
        $DB->execute($sql);
        // Define field htmleditor to be dropped from user
        $table = new xmldb_table('user');
        $field = new xmldb_field('htmleditor');
        // Conditionally launch drop field requested
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013100800.02);
    }
    if ($oldversion < 2013100900.0) {
        // Define field lifetime to be dropped from files_reference.
        $table = new xmldb_table('files_reference');
        $field = new xmldb_field('lifetime');
        // Conditionally launch drop field lifetime.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013100900.0);
    }
    if ($oldversion < 2013100901.0) {
        // Fixing possible wrong MIME type for Java Network Launch Protocol (JNLP) files.
        $select = $DB->sql_like('filename', '?', false);
        $DB->set_field_select('files', 'mimetype', 'application/x-java-jnlp-file', $select, array('%.jnlp'));
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013100901.0);
    }
    if ($oldversion < 2013102100.0) {
        // Changing default value for the status of a course backup.
        $table = new xmldb_table('backup_courses');
        $field = new xmldb_field('laststatus', XMLDB_TYPE_CHAR, '1', null, XMLDB_NOTNULL, null, '5', 'lastendtime');
        // Launch change of precision for field value
        $dbman->change_field_precision($table, $field);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013102100.0);
    }
    if ($oldversion < 2013102201.0) {
        $params = array('plugin' => 'editor_atto', 'name' => 'version');
        $attoversion = $DB->get_record('config_plugins', $params, 'value', IGNORE_MISSING);
        if ($attoversion) {
            $attoversion = floatval($attoversion->value);
        }
        // Only these versions that were part of 2.6 beta should be removed.
        // Manually installed versions of 2.5 - or later releases for 2.6 installed
        // via the plugins DB should not be uninstalled.
        if ($attoversion && $attoversion > 2013051500.0 && $attoversion < 2013102201.0) {
            // Remove all other associated config.
            unset_all_config_for_plugin('editor_atto');
            unset_all_config_for_plugin('atto_bold');
            unset_all_config_for_plugin('atto_clear');
            unset_all_config_for_plugin('atto_html');
            unset_all_config_for_plugin('atto_image');
            unset_all_config_for_plugin('atto_indent');
            unset_all_config_for_plugin('atto_italic');
            unset_all_config_for_plugin('atto_link');
            unset_all_config_for_plugin('atto_media');
            unset_all_config_for_plugin('atto_orderedlist');
            unset_all_config_for_plugin('atto_outdent');
            unset_all_config_for_plugin('atto_strike');
            unset_all_config_for_plugin('atto_title');
            unset_all_config_for_plugin('atto_underline');
            unset_all_config_for_plugin('atto_unlink');
            unset_all_config_for_plugin('atto_unorderedlist');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013102201.0);
    }
    if ($oldversion < 2013102500.01) {
        // Find all fileareas that have missing root folder entry and add the root folder entry.
        if (empty($CFG->filesrootrecordsfixed)) {
            upgrade_fix_missing_root_folders();
            // To skip running the same script on the upgrade to the next major release.
            set_config('filesrootrecordsfixed', 1);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013102500.01);
    }
    if ($oldversion < 2013110500.01) {
        // MDL-38228. Corrected course_modules upgrade script instead of 2013021801.01.
        // This upgrade script fixes the mismatches between DB fields course_modules.section
        // and course_sections.sequence. It makes sure that each module is included
        // in the sequence of at least one section.
        // There is also a separate script for admins: admin/cli/fix_course_sortorder.php
        // This script in included in each major version upgrade process so make sure we don't run it twice.
        if (empty($CFG->movingmoduleupgradescriptwasrun)) {
            upgrade_course_modules_sequences();
            // To skip running the same script on the upgrade to the next major release.
            set_config('movingmoduleupgradescriptwasrun', 1);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013110500.01);
    }
    if ($oldversion < 2013110600.01) {
        if (!file_exists($CFG->dirroot . '/theme/mymobile')) {
            // Replace the mymobile settings.
            $DB->set_field('course', 'theme', 'clean', array('theme' => 'mymobile'));
            $DB->set_field('course_categories', 'theme', 'clean', array('theme' => 'mymobile'));
            $DB->set_field('user', 'theme', 'clean', array('theme' => 'mymobile'));
            $DB->set_field('mnet_host', 'theme', 'clean', array('theme' => 'mymobile'));
            // Replace the theme configs.
            if (get_config('core', 'theme') === 'mymobile') {
                set_config('theme', 'clean');
            }
            if (get_config('core', 'thememobile') === 'mymobile') {
                set_config('thememobile', 'clean');
            }
            if (get_config('core', 'themelegacy') === 'mymobile') {
                set_config('themelegacy', 'clean');
            }
            if (get_config('core', 'themetablet') === 'mymobile') {
                set_config('themetablet', 'clean');
            }
            // Hacky emulation of plugin uninstallation.
            unset_all_config_for_plugin('theme_mymobile');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013110600.01);
    }
    if ($oldversion < 2013110600.02) {
        // If the user is logged in, we ensure that the alternate name fields are present
        // in the session. It will not be the case when upgrading from 2.5 downwards.
        if (!empty($USER->id)) {
            $refreshuser = $DB->get_record('user', array('id' => $USER->id));
            $fields = array('firstnamephonetic', 'lastnamephonetic', 'middlename', 'alternatename', 'firstname', 'lastname');
            foreach ($fields as $field) {
                $USER->{$field} = $refreshuser->{$field};
            }
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013110600.02);
    }
    // Moodle v2.6.0 release upgrade line.
    // Put any upgrade step following this.
    if ($oldversion < 2013111800.01) {
        // Delete notes of deleted courses.
        $sql = "DELETE FROM {post}\n                 WHERE NOT EXISTS (SELECT {course}.id FROM {course}\n                                    WHERE {course}.id = {post}.courseid)\n                       AND {post}.module = ?";
        $DB->execute($sql, array('notes'));
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013111800.01);
    }
    if ($oldversion < 2013122400.01) {
        // Purge stored passwords from config_log table, ideally this should be in each plugin
        // but that would complicate backporting...
        $items = array('core/cronremotepassword', 'core/proxypassword', 'core/smtppass', 'core/jabberpassword', 'enrol_database/dbpass', 'enrol_ldap/bind_pw', 'url/secretphrase');
        foreach ($items as $item) {
            list($plugin, $name) = explode('/', $item);
            $sqlcomparevalue = $DB->sql_compare_text('value');
            $sqlcompareoldvalue = $DB->sql_compare_text('oldvalue');
            if ($plugin === 'core') {
                $sql = "UPDATE {config_log}\n                           SET value = :value\n                         WHERE name = :name AND plugin IS NULL AND {$sqlcomparevalue} <> :empty";
                $params = array('value' => '********', 'name' => $name, 'empty' => '');
                $DB->execute($sql, $params);
                $sql = "UPDATE {config_log}\n                           SET oldvalue = :value\n                         WHERE name = :name AND plugin IS NULL AND {$sqlcompareoldvalue} <> :empty";
                $params = array('value' => '********', 'name' => $name, 'empty' => '');
                $DB->execute($sql, $params);
            } else {
                $sql = "UPDATE {config_log}\n                           SET value = :value\n                         WHERE name = :name AND plugin = :plugin AND {$sqlcomparevalue} <> :empty";
                $params = array('value' => '********', 'name' => $name, 'plugin' => $plugin, 'empty' => '');
                $DB->execute($sql, $params);
                $sql = "UPDATE {config_log}\n                           SET oldvalue = :value\n                         WHERE name = :name AND plugin = :plugin AND  {$sqlcompareoldvalue} <> :empty";
                $params = array('value' => '********', 'name' => $name, 'plugin' => $plugin, 'empty' => '');
                $DB->execute($sql, $params);
            }
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2013122400.01);
    }
    if ($oldversion < 2014011000.01) {
        // Define table cache_text to be dropped.
        $table = new xmldb_table('cache_text');
        // Conditionally launch drop table for cache_text.
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        unset_config('cachetext');
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014011000.01);
    }
    if ($oldversion < 2014011701.0) {
        // Fix gradebook sortorder duplicates.
        upgrade_grade_item_fix_sortorder();
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014011701.0);
    }
    if ($oldversion < 2014012300.01) {
        // Remove deleted users home pages.
        $sql = "DELETE FROM {my_pages}\n                WHERE EXISTS (SELECT {user}.id\n                                  FROM {user}\n                                  WHERE {user}.id = {my_pages}.userid\n                                  AND {user}.deleted = 1)\n                AND {my_pages}.private = 1";
        $DB->execute($sql);
        // Reached main savepoint.
        upgrade_main_savepoint(true, 2014012300.01);
    }
    if ($oldversion < 2014012400.0) {
        // Define table lock_db to be created.
        $table = new xmldb_table('lock_db');
        // Adding fields to table lock_db.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('resourcekey', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('expires', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('owner', XMLDB_TYPE_CHAR, '36', null, null, null, null);
        // Adding keys to table lock_db.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table lock_db.
        $table->add_index('resourcekey_uniq', XMLDB_INDEX_UNIQUE, array('resourcekey'));
        $table->add_index('expires_idx', XMLDB_INDEX_NOTUNIQUE, array('expires'));
        $table->add_index('owner_idx', XMLDB_INDEX_NOTUNIQUE, array('owner'));
        // Conditionally launch create table for lock_db.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014012400.0);
    }
    if ($oldversion < 2014021300.01) {
        // Delete any cached stats to force recalculation later, then we can be sure that cached records will have the correct
        // field.
        $DB->delete_records('question_response_analysis');
        $DB->delete_records('question_statistics');
        $DB->delete_records('quiz_statistics');
        // Define field variant to be added to question_statistics.
        $table = new xmldb_table('question_statistics');
        $field = new xmldb_field('variant', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'subquestion');
        // Conditionally launch add field variant.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014021300.01);
    }
    if ($oldversion < 2014021300.02) {
        // Define field variant to be added to question_response_analysis.
        $table = new xmldb_table('question_response_analysis');
        $field = new xmldb_field('variant', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'questionid');
        // Conditionally launch add field variant.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014021300.02);
    }
    if ($oldversion < 2014021800.0) {
        // Define field queued to be added to portfolio_tempdata.
        $table = new xmldb_table('portfolio_tempdata');
        $field = new xmldb_field('queued', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'instance');
        // Conditionally launch add field queued.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014021800.0);
    }
    if ($oldversion < 2014021900.01) {
        // Force uninstall of deleted tool.
        // Normally, in this sort of situation, we would do a file_exists check,
        // in case the plugin had been added back as an add-on. However, this
        // plugin is completely useless after Moodle 2.6, so we check that the
        // files have been removed in upgrade_stale_php_files_present, and we
        // uninstall it unconditionally here.
        // Remove all associated config.
        unset_all_config_for_plugin('tool_qeupgradehelper');
        upgrade_main_savepoint(true, 2014021900.01);
    }
    if ($oldversion < 2014021900.02) {
        // Define table question_states to be dropped.
        $table = new xmldb_table('question_states');
        // Conditionally launch drop table for question_states.
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014021900.02);
    }
    if ($oldversion < 2014021900.03) {
        // Define table question_sessions to be dropped.
        $table = new xmldb_table('question_sessions');
        // Conditionally launch drop table for question_sessions.
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014021900.03);
    }
    if ($oldversion < 2014022600.0) {
        $table = new xmldb_table('task_scheduled');
        // Adding fields to table task_scheduled.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('component', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('classname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('lastruntime', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('nextruntime', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('blocking', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('minute', XMLDB_TYPE_CHAR, '25', null, XMLDB_NOTNULL, null, null);
        $table->add_field('hour', XMLDB_TYPE_CHAR, '25', null, XMLDB_NOTNULL, null, null);
        $table->add_field('day', XMLDB_TYPE_CHAR, '25', null, XMLDB_NOTNULL, null, null);
        $table->add_field('month', XMLDB_TYPE_CHAR, '25', null, XMLDB_NOTNULL, null, null);
        $table->add_field('dayofweek', XMLDB_TYPE_CHAR, '25', null, XMLDB_NOTNULL, null, null);
        $table->add_field('faildelay', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('customised', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('disabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
        // Adding keys to table task_scheduled.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table task_scheduled.
        $table->add_index('classname_uniq', XMLDB_INDEX_UNIQUE, array('classname'));
        // Conditionally launch create table for task_scheduled.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table task_adhoc to be created.
        $table = new xmldb_table('task_adhoc');
        // Adding fields to table task_adhoc.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('component', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('classname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('nextruntime', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('faildelay', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('customdata', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('blocking', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
        // Adding keys to table task_adhoc.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table task_adhoc.
        $table->add_index('nextruntime_idx', XMLDB_INDEX_NOTUNIQUE, array('nextruntime'));
        // Conditionally launch create table for task_adhoc.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014022600.0);
    }
    if ($oldversion < 2014031400.02) {
        // Delete any cached stats to force recalculation later, then we can be sure that cached records will have the correct
        // field.
        $DB->delete_records('question_response_analysis');
        $DB->delete_records('question_statistics');
        $DB->delete_records('quiz_statistics');
        // Define field response to be dropped from question_response_analysis.
        $table = new xmldb_table('question_response_analysis');
        $field = new xmldb_field('rcount');
        // Conditionally launch drop field response.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014031400.02);
    }
    if ($oldversion < 2014031400.03) {
        // Define table question_response_count to be created.
        $table = new xmldb_table('question_response_count');
        // Adding fields to table question_response_count.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('analysisid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('try', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('rcount', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table question_response_count.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('analysisid', XMLDB_KEY_FOREIGN, array('analysisid'), 'question_response_analysis', array('id'));
        // Conditionally launch create table for question_response_count.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014031400.03);
    }
    if ($oldversion < 2014031400.04) {
        // Define field whichtries to be added to question_response_analysis.
        $table = new xmldb_table('question_response_analysis');
        $field = new xmldb_field('whichtries', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'hashcode');
        // Conditionally launch add field whichtries.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014031400.04);
    }
    if ($oldversion < 2014032600.0) {
        // Removing the themes from core.
        $themes = array('afterburner', 'anomaly', 'arialist', 'binarius', 'boxxie', 'brick', 'formal_white', 'formfactor', 'fusion', 'leatherbound', 'magazine', 'nimble', 'nonzero', 'overlay', 'serenity', 'sky_high', 'splash', 'standard', 'standardold');
        foreach ($themes as $key => $theme) {
            if (check_dir_exists($CFG->dirroot . '/theme/' . $theme, false)) {
                // Ignore the themes that have been re-downloaded.
                unset($themes[$key]);
            }
        }
        // Check we actually have themes to remove.
        if (count($themes) > 0) {
            // Replace the theme configs.
            if (in_array(get_config('core', 'theme'), $themes)) {
                set_config('theme', 'clean');
            }
            if (in_array(get_config('core', 'thememobile'), $themes)) {
                set_config('thememobile', 'clean');
            }
            if (in_array(get_config('core', 'themelegacy'), $themes)) {
                set_config('themelegacy', 'clean');
            }
            if (in_array(get_config('core', 'themetablet'), $themes)) {
                set_config('themetablet', 'clean');
            }
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014032600.0);
    }
    if ($oldversion < 2014032600.02) {
        // Add new fields to the 'tag_instance' table.
        $table = new xmldb_table('tag_instance');
        $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, false, null, null, 'tagid');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('contextid', XMLDB_TYPE_INTEGER, '10', null, false, null, null, 'itemid');
        // Define the 'contextid' foreign key to be added to the tag_instance table.
        $key = new xmldb_key('contextid', XMLDB_KEY_FOREIGN, array('contextid'), 'context', array('id'));
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_key($table, $key);
            $DB->set_field('tag_instance', 'contextid', null, array('contextid' => 0));
            $dbman->change_field_default($table, $field);
        } else {
            $dbman->add_field($table, $field);
        }
        $dbman->add_key($table, $key);
        $field = new xmldb_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'ordering');
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $sql = "UPDATE {tag_instance}\n                   SET timecreated = timemodified";
        $DB->execute($sql);
        // Update all the course tags.
        $sql = "UPDATE {tag_instance}\n                   SET component = 'core',\n                       contextid = (SELECT ctx.id\n                                      FROM {context} ctx\n                                     WHERE ctx.contextlevel = :contextlevel\n                                       AND ctx.instanceid = {tag_instance}.itemid)\n                 WHERE itemtype = 'course' AND contextid IS NULL";
        $DB->execute($sql, array('contextlevel' => CONTEXT_COURSE));
        // Update all the user tags.
        $sql = "UPDATE {tag_instance}\n                   SET component = 'core',\n                       contextid = (SELECT ctx.id\n                                      FROM {context} ctx\n                                     WHERE ctx.contextlevel = :contextlevel\n                                       AND ctx.instanceid = {tag_instance}.itemid)\n                 WHERE itemtype = 'user' AND contextid IS NULL";
        $DB->execute($sql, array('contextlevel' => CONTEXT_USER));
        // Update all the blog post tags.
        $sql = "UPDATE {tag_instance}\n                   SET component = 'core',\n                       contextid = (SELECT ctx.id\n                                      FROM {context} ctx\n                                      JOIN {post} p\n                                        ON p.userid = ctx.instanceid\n                                     WHERE ctx.contextlevel = :contextlevel\n                                       AND p.id = {tag_instance}.itemid)\n                 WHERE itemtype = 'post' AND contextid IS NULL";
        $DB->execute($sql, array('contextlevel' => CONTEXT_USER));
        // Update all the wiki page tags.
        $sql = "UPDATE {tag_instance}\n                   SET component = 'mod_wiki',\n                       contextid = (SELECT ctx.id\n                                      FROM {context} ctx\n                                      JOIN {course_modules} cm\n                                        ON cm.id = ctx.instanceid\n                                      JOIN {modules} m\n                                        ON m.id = cm.module\n                                      JOIN {wiki} w\n                                        ON w.id = cm.instance\n                                      JOIN {wiki_subwikis} sw\n                                        ON sw.wikiid = w.id\n                                      JOIN {wiki_pages} wp\n                                        ON wp.subwikiid = sw.id\n                                     WHERE m.name = 'wiki'\n                                       AND ctx.contextlevel = :contextlevel\n                                       AND wp.id = {tag_instance}.itemid)\n                 WHERE itemtype = 'wiki_pages' AND contextid IS NULL";
        $DB->execute($sql, array('contextlevel' => CONTEXT_MODULE));
        // Update all the question tags.
        $sql = "UPDATE {tag_instance}\n                   SET component = 'core_question',\n                       contextid = (SELECT qc.contextid\n                                      FROM {question} q\n                                      JOIN {question_categories} qc\n                                        ON q.category = qc.id\n                                     WHERE q.id = {tag_instance}.itemid)\n                 WHERE itemtype = 'question' AND contextid IS NULL";
        $DB->execute($sql);
        // Update all the tag tags.
        $sql = "UPDATE {tag_instance}\n                   SET component = 'core',\n                       contextid = :systemcontext\n                 WHERE itemtype = 'tag' AND contextid IS NULL";
        $DB->execute($sql, array('systemcontext' => context_system::instance()->id));
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014032600.02);
    }
    if ($oldversion < 2014032700.01) {
        // Define field disabled to be added to task_scheduled.
        $table = new xmldb_table('task_scheduled');
        $field = new xmldb_field('disabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'customised');
        // Conditionally launch add field disabled.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014032700.01);
    }
    if ($oldversion < 2014032700.02) {
        // Update displayloginfailures setting.
        if (empty($CFG->displayloginfailures)) {
            set_config('displayloginfailures', 0);
        } else {
            set_config('displayloginfailures', 1);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014032700.02);
    }
    if ($oldversion < 2014040800.0) {
        // Define field availability to be added to course_modules.
        $table = new xmldb_table('course_modules');
        $field = new xmldb_field('availability', XMLDB_TYPE_TEXT, null, null, null, null, null, 'showdescription');
        // Conditionally launch add field availability.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field availability to be added to course_sections.
        $table = new xmldb_table('course_sections');
        $field = new xmldb_field('availability', XMLDB_TYPE_TEXT, null, null, null, null, null, 'groupingid');
        // Conditionally launch add field availability.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Update existing conditions to new format. This could be a slow
        // process, so begin by counting the number of affected modules/sections.
        // (Performance: On the OU system, these took ~0.3 seconds, with about
        // 20,000 results out of about 400,000 total rows in those tables.)
        $cmcount = $DB->count_records_sql("\n                SELECT COUNT(1)\n                  FROM {course_modules} cm\n                 WHERE cm.availablefrom != 0 OR\n                       cm.availableuntil != 0 OR\n                       EXISTS (SELECT 1 FROM {course_modules_availability} WHERE coursemoduleid = cm.id) OR\n                       EXISTS (SELECT 1 FROM {course_modules_avail_fields} WHERE coursemoduleid = cm.id)");
        $sectcount = $DB->count_records_sql("\n                SELECT COUNT(1)\n                  FROM {course_sections} cs\n                 WHERE cs.groupingid != 0 OR\n                       cs.availablefrom != 0 OR\n                       cs.availableuntil != 0 OR\n                       EXISTS (SELECT 1 FROM {course_sections_availability} WHERE coursesectionid = cs.id) OR\n                       EXISTS (SELECT 1 FROM {course_sections_avail_fields} WHERE coursesectionid = cs.id)");
        if ($cmcount + $sectcount > 0) {
            // Show progress bar and start db transaction.
            $transaction = $DB->start_delegated_transaction();
            $pbar = new progress_bar('availupdate', 500, true);
            // Loop through all course-modules.
            // (Performance: On the OU system, the query took <1 second for ~20k
            // results; updating all those entries took ~3 minutes.)
            $done = 0;
            $lastupdate = 0;
            $rs = $DB->get_recordset_sql("\n                    SELECT cm.id, cm.availablefrom, cm.availableuntil, cm.showavailability,\n                           COUNT(DISTINCT cma.id) AS availcount,\n                           COUNT(DISTINCT cmf.id) AS fieldcount\n                      FROM {course_modules} cm\n                           LEFT JOIN {course_modules_availability} cma ON cma.coursemoduleid = cm.id\n                           LEFT JOIN {course_modules_avail_fields} cmf ON cmf.coursemoduleid = cm.id\n                     WHERE cm.availablefrom != 0 OR\n                           cm.availableuntil != 0 OR\n                           cma.id IS NOT NULL OR\n                           cmf.id IS NOT NULL\n                  GROUP BY cm.id, cm.availablefrom, cm.availableuntil, cm.showavailability");
            foreach ($rs as $rec) {
                // Update progress initially and then once per second.
                if (time() != $lastupdate) {
                    $lastupdate = time();
                    $pbar->update($done, $cmcount + $sectcount, "Updating activity availability settings ({$done}/{$cmcount})");
                }
                // Get supporting records - only if there are any (to reduce the
                // number of queries where just date/group is used).
                if ($rec->availcount) {
                    $availrecs = $DB->get_records('course_modules_availability', array('coursemoduleid' => $rec->id));
                } else {
                    $availrecs = array();
                }
                if ($rec->fieldcount) {
                    $fieldrecs = $DB->get_records_sql("\n                            SELECT cmaf.userfield, cmaf.operator, cmaf.value, uif.shortname\n                              FROM {course_modules_avail_fields} cmaf\n                         LEFT JOIN {user_info_field} uif ON uif.id = cmaf.customfieldid\n                             WHERE cmaf.coursemoduleid = ?", array($rec->id));
                } else {
                    $fieldrecs = array();
                }
                // Update item.
                $availability = upgrade_availability_item(0, 0, $rec->availablefrom, $rec->availableuntil, $rec->showavailability, $availrecs, $fieldrecs);
                if ($availability) {
                    $DB->set_field('course_modules', 'availability', $availability, array('id' => $rec->id));
                }
                // Update progress.
                $done++;
            }
            $rs->close();
            // Loop through all course-sections.
            // (Performance: On the OU system, this took <1 second for, er, 150 results.)
            $done = 0;
            $rs = $DB->get_recordset_sql("\n                    SELECT cs.id, cs.groupingid, cs.availablefrom,\n                           cs.availableuntil, cs.showavailability,\n                           COUNT(DISTINCT csa.id) AS availcount,\n                           COUNT(DISTINCT csf.id) AS fieldcount\n                      FROM {course_sections} cs\n                           LEFT JOIN {course_sections_availability} csa ON csa.coursesectionid = cs.id\n                           LEFT JOIN {course_sections_avail_fields} csf ON csf.coursesectionid = cs.id\n                     WHERE cs.groupingid != 0 OR\n                           cs.availablefrom != 0 OR\n                           cs.availableuntil != 0 OR\n                           csa.id IS NOT NULL OR\n                           csf.id IS NOT NULL\n                  GROUP BY cs.id, cs.groupingid, cs.availablefrom,\n                           cs.availableuntil, cs.showavailability");
            foreach ($rs as $rec) {
                // Update progress once per second.
                if (time() != $lastupdate) {
                    $lastupdate = time();
                    $pbar->update($done + $cmcount, $cmcount + $sectcount, "Updating section availability settings ({$done}/{$sectcount})");
                }
                // Get supporting records - only if there are any (to reduce the
                // number of queries where just date/group is used).
                if ($rec->availcount) {
                    $availrecs = $DB->get_records('course_sections_availability', array('coursesectionid' => $rec->id));
                } else {
                    $availrecs = array();
                }
                if ($rec->fieldcount) {
                    $fieldrecs = $DB->get_records_sql("\n                            SELECT csaf.userfield, csaf.operator, csaf.value, uif.shortname\n                              FROM {course_sections_avail_fields} csaf\n                         LEFT JOIN {user_info_field} uif ON uif.id = csaf.customfieldid\n                             WHERE csaf.coursesectionid = ?", array($rec->id));
                } else {
                    $fieldrecs = array();
                }
                // Update item.
                $availability = upgrade_availability_item($rec->groupingid ? 1 : 0, $rec->groupingid, $rec->availablefrom, $rec->availableuntil, $rec->showavailability, $availrecs, $fieldrecs);
                if ($availability) {
                    $DB->set_field('course_sections', 'availability', $availability, array('id' => $rec->id));
                }
                // Update progress.
                $done++;
            }
            $rs->close();
            // Final progress update for 100%.
            $pbar->update($done + $cmcount, $cmcount + $sectcount, 'Availability settings updated for ' . ($cmcount + $sectcount) . ' activities and sections');
            $transaction->allow_commit();
        }
        // Drop tables which are not necessary because they are covered by the
        // new availability fields.
        $table = new xmldb_table('course_modules_availability');
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        $table = new xmldb_table('course_modules_avail_fields');
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        $table = new xmldb_table('course_sections_availability');
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        $table = new xmldb_table('course_sections_avail_fields');
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        // Drop unnnecessary fields from course_modules.
        $table = new xmldb_table('course_modules');
        $field = new xmldb_field('availablefrom');
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        $field = new xmldb_field('availableuntil');
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        $field = new xmldb_field('showavailability');
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Drop unnnecessary fields from course_sections.
        $table = new xmldb_table('course_sections');
        $field = new xmldb_field('availablefrom');
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        $field = new xmldb_field('availableuntil');
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        $field = new xmldb_field('showavailability');
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        $field = new xmldb_field('groupingid');
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014040800.0);
    }
    if ($oldversion < 2014041500.01) {
        $table = new xmldb_table('user_info_data');
        $sql = 'SELECT DISTINCT info.id
                  FROM {user_info_data} info
            INNER JOIN {user_info_data} older
                    ON info.fieldid = older.fieldid
                   AND info.userid = older.userid
                   AND older.id < info.id';
        $transaction = $DB->start_delegated_transaction();
        $rs = $DB->get_recordset_sql($sql);
        foreach ($rs as $rec) {
            $DB->delete_records('user_info_data', array('id' => $rec->id));
        }
        $transaction->allow_commit();
        $oldindex = new xmldb_index('userid_fieldid', XMLDB_INDEX_NOTUNIQUE, array('userid', 'fieldid'));
        if ($dbman->index_exists($table, $oldindex)) {
            $dbman->drop_index($table, $oldindex);
        }
        $newindex = new xmldb_index('userid_fieldid', XMLDB_INDEX_UNIQUE, array('userid', 'fieldid'));
        if (!$dbman->index_exists($table, $newindex)) {
            $dbman->add_index($table, $newindex);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014041500.01);
    }
    if ($oldversion < 2014050100.0) {
        // Fixing possible wrong MIME type for DigiDoc files.
        $extensions = array('%.bdoc', '%.cdoc', '%.ddoc');
        $select = $DB->sql_like('filename', '?', false);
        foreach ($extensions as $extension) {
            $DB->set_field_select('files', 'mimetype', 'application/x-digidoc', $select, array($extension));
        }
        upgrade_main_savepoint(true, 2014050100.0);
    }
    // Moodle v2.7.0 release upgrade line.
    // Put any upgrade step following this.
    // MDL-32543 Make sure that the log table has correct length for action and url fields.
    if ($oldversion < 2014051200.02) {
        $table = new xmldb_table('log');
        $columns = $DB->get_columns('log');
        if ($columns['action']->max_length < 40) {
            $index1 = new xmldb_index('course-module-action', XMLDB_INDEX_NOTUNIQUE, array('course', 'module', 'action'));
            if ($dbman->index_exists($table, $index1)) {
                $dbman->drop_index($table, $index1);
            }
            $index2 = new xmldb_index('action', XMLDB_INDEX_NOTUNIQUE, array('action'));
            if ($dbman->index_exists($table, $index2)) {
                $dbman->drop_index($table, $index2);
            }
            $field = new xmldb_field('action', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null, 'cmid');
            $dbman->change_field_precision($table, $field);
            $dbman->add_index($table, $index1);
            $dbman->add_index($table, $index2);
        }
        if ($columns['url']->max_length < 100) {
            $field = new xmldb_field('url', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'action');
            $dbman->change_field_precision($table, $field);
        }
        upgrade_main_savepoint(true, 2014051200.02);
    }
    if ($oldversion < 2014060300.0) {
        $gspath = get_config('assignfeedback_editpdf', 'gspath');
        if ($gspath !== false) {
            set_config('pathtogs', $gspath);
            unset_config('gspath', 'assignfeedback_editpdf');
        }
        upgrade_main_savepoint(true, 2014060300.0);
    }
    if ($oldversion < 2014061000.0) {
        // Fixing possible wrong MIME type for Publisher files.
        $filetypes = array('%.pub' => 'application/x-mspublisher');
        upgrade_mimetypes($filetypes);
        upgrade_main_savepoint(true, 2014061000.0);
    }
    if ($oldversion < 2014062600.01) {
        // We only want to delete DragMath if the directory no longer exists. If the directory
        // is present then it means it has been restored, so do not perform the uninstall.
        if (!check_dir_exists($CFG->libdir . '/editor/tinymce/plugins/dragmath', false)) {
            // Purge DragMath plugin which is incompatible with GNU GPL license.
            unset_all_config_for_plugin('tinymce_dragmath');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014062600.01);
    }
    // Switch the order of the fields in the files_reference index, to improve the performance of search_references.
    if ($oldversion < 2014070100.0) {
        $table = new xmldb_table('files_reference');
        $index = new xmldb_index('uq_external_file', XMLDB_INDEX_UNIQUE, array('repositoryid', 'referencehash'));
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        upgrade_main_savepoint(true, 2014070100.0);
    }
    if ($oldversion < 2014070101.0) {
        $table = new xmldb_table('files_reference');
        $index = new xmldb_index('uq_external_file', XMLDB_INDEX_UNIQUE, array('referencehash', 'repositoryid'));
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        upgrade_main_savepoint(true, 2014070101.0);
    }
    if ($oldversion < 2014072400.01) {
        $table = new xmldb_table('user_devices');
        $oldindex = new xmldb_index('pushid-platform', XMLDB_KEY_UNIQUE, array('pushid', 'platform'));
        if ($dbman->index_exists($table, $oldindex)) {
            $key = new xmldb_key('pushid-platform', XMLDB_KEY_UNIQUE, array('pushid', 'platform'));
            $dbman->drop_key($table, $key);
        }
        upgrade_main_savepoint(true, 2014072400.01);
    }
    if ($oldversion < 2014080801.0) {
        // Define index behaviour (not unique) to be added to question_attempts.
        $table = new xmldb_table('question_attempts');
        $index = new xmldb_index('behaviour', XMLDB_INDEX_NOTUNIQUE, array('behaviour'));
        // Conditionally launch add index behaviour.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014080801.0);
    }
    if ($oldversion < 2014082900.01) {
        // Fixing possible wrong MIME type for 7-zip and Rar files.
        $filetypes = array('%.7z' => 'application/x-7z-compressed', '%.rar' => 'application/x-rar-compressed');
        upgrade_mimetypes($filetypes);
        upgrade_main_savepoint(true, 2014082900.01);
    }
    if ($oldversion < 2014082900.02) {
        // Replace groupmembersonly usage with new availability system.
        $transaction = $DB->start_delegated_transaction();
        if ($CFG->enablegroupmembersonly) {
            // If it isn't already enabled, we need to enable availability.
            if (!$CFG->enableavailability) {
                set_config('enableavailability', 1);
            }
            // Count all course-modules with groupmembersonly set (for progress
            // bar).
            $total = $DB->count_records('course_modules', array('groupmembersonly' => 1));
            $pbar = new progress_bar('upgradegroupmembersonly', 500, true);
            // Get all these course-modules, one at a time.
            $rs = $DB->get_recordset('course_modules', array('groupmembersonly' => 1), 'course, id');
            $i = 0;
            foreach ($rs as $cm) {
                // Calculate and set new availability value.
                $availability = upgrade_group_members_only($cm->groupingid, $cm->availability);
                $DB->set_field('course_modules', 'availability', $availability, array('id' => $cm->id));
                // Update progress.
                $i++;
                $pbar->update($i, $total, "Upgrading groupmembersonly settings - {$i}/{$total}.");
            }
            $rs->close();
        }
        // Define field groupmembersonly to be dropped from course_modules.
        $table = new xmldb_table('course_modules');
        $field = new xmldb_field('groupmembersonly');
        // Conditionally launch drop field groupmembersonly.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Unset old config variable.
        unset_config('enablegroupmembersonly');
        $transaction->allow_commit();
        upgrade_main_savepoint(true, 2014082900.02);
    }
    if ($oldversion < 2014100100.0) {
        // Define table messageinbound_handlers to be created.
        $table = new xmldb_table('messageinbound_handlers');
        // Adding fields to table messageinbound_handlers.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
        $table->add_field('classname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('defaultexpiration', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '86400');
        $table->add_field('validateaddress', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1');
        $table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
        // Adding keys to table messageinbound_handlers.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('classname', XMLDB_KEY_UNIQUE, array('classname'));
        // Conditionally launch create table for messageinbound_handlers.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table messageinbound_datakeys to be created.
        $table = new xmldb_table('messageinbound_datakeys');
        // Adding fields to table messageinbound_datakeys.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('handler', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('datavalue', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('datakey', XMLDB_TYPE_CHAR, '64', null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('expires', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        // Adding keys to table messageinbound_datakeys.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('handler_datavalue', XMLDB_KEY_UNIQUE, array('handler', 'datavalue'));
        $table->add_key('handler', XMLDB_KEY_FOREIGN, array('handler'), 'messageinbound_handlers', array('id'));
        // Conditionally launch create table for messageinbound_datakeys.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100100.0);
    }
    if ($oldversion < 2014100600.01) {
        // Define field aggregationstatus to be added to grade_grades.
        $table = new xmldb_table('grade_grades');
        $field = new xmldb_field('aggregationstatus', XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, 'unknown', 'timemodified');
        // Conditionally launch add field aggregationstatus.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('aggregationweight', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null, 'aggregationstatus');
        // Conditionally launch add field aggregationweight.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field aggregationcoef2 to be added to grade_items.
        $table = new xmldb_table('grade_items');
        $field = new xmldb_field('aggregationcoef2', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, '0', 'aggregationcoef');
        // Conditionally launch add field aggregationcoef2.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('weightoverride', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'needsupdate');
        // Conditionally launch add field weightoverride.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100600.01);
    }
    if ($oldversion < 2014100600.02) {
        // Define field aggregationcoef2 to be added to grade_items_history.
        $table = new xmldb_table('grade_items_history');
        $field = new xmldb_field('aggregationcoef2', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, '0', 'aggregationcoef');
        // Conditionally launch add field aggregationcoef2.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100600.02);
    }
    if ($oldversion < 2014100600.03) {
        // Define field weightoverride to be added to grade_items_history.
        $table = new xmldb_table('grade_items_history');
        $field = new xmldb_field('weightoverride', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'decimals');
        // Conditionally launch add field weightoverride.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100600.03);
    }
    if ($oldversion < 2014100600.04) {
        // Set flags so we can display a notice on all courses that might
        // be affected by the uprade to natural aggregation.
        if (!get_config('grades_sumofgrades_upgrade_flagged', 'core')) {
            // 13 == SUM_OF_GRADES.
            $sql = 'SELECT DISTINCT courseid
                      FROM {grade_categories}
                     WHERE aggregation = ?';
            $courses = $DB->get_records_sql($sql, array(13));
            foreach ($courses as $course) {
                set_config('show_sumofgrades_upgrade_' . $course->courseid, 1);
                // Set each of the grade items to needing an update so that when the user visits the grade reports the
                // figures will be updated.
                $DB->set_field('grade_items', 'needsupdate', 1, array('courseid' => $course->courseid));
            }
            set_config('grades_sumofgrades_upgrade_flagged', 1);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100600.04);
    }
    if ($oldversion < 2014100700.0) {
        // Define table messageinbound_messagelist to be created.
        $table = new xmldb_table('messageinbound_messagelist');
        // Adding fields to table messageinbound_messagelist.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('messageid', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('address', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table messageinbound_messagelist.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
        // Conditionally launch create table for messageinbound_messagelist.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100700.0);
    }
    if ($oldversion < 2014100700.01) {
        // Define field visible to be added to cohort.
        $table = new xmldb_table('cohort');
        $field = new xmldb_field('visible', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'descriptionformat');
        // Conditionally launch add field visible.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100700.01);
    }
    if ($oldversion < 2014100800.0) {
        // Remove qformat_learnwise (unless it has manually been added back).
        if (!file_exists($CFG->dirroot . '/question/format/learnwise/format.php')) {
            unset_all_config_for_plugin('qformat_learnwise');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100800.0);
    }
    if ($oldversion < 2014101001.0) {
        // Some blocks added themselves to the my/ home page, but they did not declare the
        // subpage of the default my home page. While the upgrade script has been fixed, this
        // upgrade script will fix the data that was wrongly added.
        // We only proceed if we can find the right entry from my_pages. Private => 1 refers to
        // the constant value MY_PAGE_PRIVATE.
        if ($systempage = $DB->get_record('my_pages', array('userid' => null, 'private' => 1))) {
            // Select the blocks there could have been automatically added. showinsubcontexts is hardcoded to 0
            // because it is possible for administrators to have forced it on the my/ page by adding it to the
            // system directly rather than updating the default my/ page.
            $blocks = array('course_overview', 'private_files', 'online_users', 'badges', 'calendar_month', 'calendar_upcoming');
            list($blocksql, $blockparams) = $DB->get_in_or_equal($blocks, SQL_PARAMS_NAMED);
            $select = "parentcontextid = :contextid\n                    AND pagetypepattern = :page\n                    AND showinsubcontexts = 0\n                    AND subpagepattern IS NULL\n                    AND blockname {$blocksql}";
            $params = array('contextid' => context_system::instance()->id, 'page' => 'my-index');
            $params = array_merge($params, $blockparams);
            $DB->set_field_select('block_instances', 'subpagepattern', $systempage->id, $select, $params);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014101001.0);
    }
    if ($oldversion < 2014102000.0) {
        // Define field aggregatesubcats to be dropped from grade_categories.
        $table = new xmldb_table('grade_categories');
        $field = new xmldb_field('aggregatesubcats');
        // Conditionally launch drop field aggregatesubcats.
        if ($dbman->field_exists($table, $field)) {
            $sql = 'SELECT DISTINCT courseid
                      FROM {grade_categories}
                     WHERE aggregatesubcats = ?';
            $courses = $DB->get_records_sql($sql, array(1));
            foreach ($courses as $course) {
                set_config('show_aggregatesubcats_upgrade_' . $course->courseid, 1);
                // Set each of the grade items to needing an update so that when the user visits the grade reports the
                // figures will be updated.
                $DB->set_field('grade_items', 'needsupdate', 1, array('courseid' => $course->courseid));
            }
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014102000.0);
    }
    return true;
}
 /**
  * Changes the sort order of this categories parent shifting this category up or down one.
  *
  * @global \moodle_database $DB
  * @param bool $up If set to true the category is shifted up one spot, else its moved down.
  * @return bool True on success, false otherwise.
  */
 public function change_sortorder_by_one($up)
 {
     global $DB;
     $params = array($this->sortorder, $this->parent);
     if ($up) {
         $select = 'sortorder < ? AND parent = ?';
         $sort = 'sortorder DESC';
     } else {
         $select = 'sortorder > ? AND parent = ?';
         $sort = 'sortorder ASC';
     }
     fix_course_sortorder();
     $swapcategory = $DB->get_records_select('course_categories', $select, $params, $sort, '*', 0, 1);
     $swapcategory = reset($swapcategory);
     if ($swapcategory) {
         $DB->set_field('course_categories', 'sortorder', $swapcategory->sortorder, array('id' => $this->id));
         $DB->set_field('course_categories', 'sortorder', $this->sortorder, array('id' => $swapcategory->id));
         $this->sortorder = $swapcategory->sortorder;
         $event = \core\event\course_category_updated::create(array('objectid' => $this->id, 'context' => $this->get_context()));
         $event->set_legacy_logdata(array(SITEID, 'category', 'move', 'management.php?categoryid=' . $this->id, $this->id));
         $event->trigger();
         // Finally reorder courses.
         fix_course_sortorder();
         cache_helper::purge_by_event('changesincoursecat');
         return true;
     }
     return false;
 }
Example #7
0
    /**
     * Purge dataroot directory
     * @static
     * @return void
     */
    public static function reset_dataroot() {
        global $CFG;

        $childclassname = self::get_framework() . '_util';

        $handle = opendir($CFG->dataroot);
        while (false !== ($item = readdir($handle))) {
            if (in_array($item, $childclassname::$datarootskiponreset)) {
                continue;
            }
            if (is_dir("$CFG->dataroot/$item")) {
                remove_dir("$CFG->dataroot/$item", false);
            } else {
                unlink("$CFG->dataroot/$item");
            }
        }
        closedir($handle);
        make_temp_directory('');
        make_cache_directory('');
        make_cache_directory('htmlpurifier');
        // Reset the cache API so that it recreates it's required directories as well.
        cache_factory::reset();
        // Purge all data from the caches. This is required for consistency.
        // Any file caches that happened to be within the data root will have already been clearer (because we just deleted cache)
        // and now we will purge any other caches as well.
        cache_helper::purge_all();
    }
Example #8
0
/**
 * Uninstall a message processor
 *
 * @param string $name A message processor name like 'email', 'jabber'
 */
function message_processor_uninstall($name) {
    global $DB;

    $transaction = $DB->start_delegated_transaction();
    $DB->delete_records('message_processors', array('name' => $name));
    $DB->delete_records_select('config_plugins', "plugin = ?", array("message_{$name}"));
    // delete permission preferences only, we do not care about loggedin/loggedoff
    // defaults, they will be removed on the next attempt to update the preferences
    $DB->delete_records_select('config_plugins', "plugin = 'message' AND ".$DB->sql_like('name', '?', false), array("{$name}_provider_%"));
    $transaction->allow_commit();
    // Purge all messaging settings from the caches. They are stored by plugin so we have to clear all message settings.
    cache_helper::invalidate_by_definition('core', 'config', array(), array('message', "message_{$name}"));
}
Example #9
0
        if ($movecourse = $DB->get_record('course', array('id' => $moveup))) {
            $swapcourse = $DB->get_record('course', array('sortorder' => $movecourse->sortorder - 1));
        }
    } else {
        if ($movecourse = $DB->get_record('course', array('id' => $movedown))) {
            $swapcourse = $DB->get_record('course', array('sortorder' => $movecourse->sortorder + 1));
        }
    }
    if ($swapcourse and $movecourse) {
        // Check course's category.
        if ($movecourse->category != $id) {
            print_error('coursedoesnotbelongtocategory');
        }
        $DB->set_field('course', 'sortorder', $swapcourse->sortorder, array('id' => $movecourse->id));
        $DB->set_field('course', 'sortorder', $movecourse->sortorder, array('id' => $swapcourse->id));
        cache_helper::purge_by_event('changesincourse');
        add_to_log($movecourse->id, "course", "move", "edit.php?id=$movecourse->id", $movecourse->id);
    }
}

// Prepare the standard URL params for this page. We'll need them later.
$urlparams = array('categoryid' => $id);
if ($page) {
    $urlparams['page'] = $page;
}
if ($perpage) {
    $urlparams['perpage'] = $perpage;
}
$urlparams += $searchcriteria;

$PAGE->set_pagelayout('coursecategory');
Example #10
0
 /**
  * Show course category and restores visibility for child course and subcategories
  *
  * Note that there is no capability check inside this function
  *
  * This function does not update field course_categories.timemodified
  * If you want to update timemodified, use
  * $coursecat->update(array('visible' => 1));
  */
 public function show()
 {
     if ($this->show_raw()) {
         cache_helper::purge_by_event('changesincoursecat');
         add_to_log(SITEID, "category", "show", "editcategory.php?id={$this->id}", $this->id);
     }
 }
Example #11
0
 /**
  * Purge dataroot directory
  * @static
  * @return void
  */
 public static function reset_dataroot()
 {
     global $CFG;
     $childclassname = self::get_framework() . '_util';
     // Do not delete automatically installed files.
     self::skip_original_data_files($childclassname);
     // Clear file status cache, before checking file_exists.
     clearstatcache();
     // Clean up the dataroot folder.
     $handle = opendir(self::get_dataroot());
     while (false !== ($item = readdir($handle))) {
         if (in_array($item, $childclassname::$datarootskiponreset)) {
             continue;
         }
         if (is_dir(self::get_dataroot() . "/{$item}")) {
             remove_dir(self::get_dataroot() . "/{$item}", false);
         } else {
             unlink(self::get_dataroot() . "/{$item}");
         }
     }
     closedir($handle);
     // Clean up the dataroot/filedir folder.
     if (file_exists(self::get_dataroot() . '/filedir')) {
         $handle = opendir(self::get_dataroot() . '/filedir');
         while (false !== ($item = readdir($handle))) {
             if (in_array('filedir/' . $item, $childclassname::$datarootskiponreset)) {
                 continue;
             }
             if (is_dir(self::get_dataroot() . "/filedir/{$item}")) {
                 remove_dir(self::get_dataroot() . "/filedir/{$item}", false);
             } else {
                 unlink(self::get_dataroot() . "/filedir/{$item}");
             }
         }
         closedir($handle);
     }
     make_temp_directory('');
     make_cache_directory('');
     make_localcache_directory('');
     // Reset the cache API so that it recreates it's required directories as well.
     cache_factory::reset();
     // Purge all data from the caches. This is required for consistency.
     // Any file caches that happened to be within the data root will have already been clearer (because we just deleted cache)
     // and now we will purge any other caches as well.
     cache_helper::purge_all();
 }
/**
 * get_performance_info() pairs up with init_performance_info()
 * loaded in setup.php. Returns an array with 'html' and 'txt'
 * values ready for use, and each of the individual stats provided
 * separately as well.
 *
 * @return array
 */
function get_performance_info()
{
    global $CFG, $PERF, $DB, $PAGE;
    $info = array();
    $info['html'] = '';
    // Holds userfriendly HTML representation.
    $info['txt'] = me() . ' ';
    // Holds log-friendly representation.
    $info['realtime'] = microtime_diff($PERF->starttime, microtime());
    $info['html'] .= '<span class="timeused">' . $info['realtime'] . ' secs</span> ';
    $info['txt'] .= 'time: ' . $info['realtime'] . 's ';
    if (function_exists('memory_get_usage')) {
        $info['memory_total'] = memory_get_usage();
        $info['memory_growth'] = memory_get_usage() - $PERF->startmemory;
        $info['html'] .= '<span class="memoryused">RAM: ' . display_size($info['memory_total']) . '</span> ';
        $info['txt'] .= 'memory_total: ' . $info['memory_total'] . 'B (' . display_size($info['memory_total']) . ') memory_growth: ' . $info['memory_growth'] . 'B (' . display_size($info['memory_growth']) . ') ';
    }
    if (function_exists('memory_get_peak_usage')) {
        $info['memory_peak'] = memory_get_peak_usage();
        $info['html'] .= '<span class="memoryused">RAM peak: ' . display_size($info['memory_peak']) . '</span> ';
        $info['txt'] .= 'memory_peak: ' . $info['memory_peak'] . 'B (' . display_size($info['memory_peak']) . ') ';
    }
    $inc = get_included_files();
    $info['includecount'] = count($inc);
    $info['html'] .= '<span class="included">Included ' . $info['includecount'] . ' files</span> ';
    $info['txt'] .= 'includecount: ' . $info['includecount'] . ' ';
    if (!empty($CFG->early_install_lang) or empty($PAGE)) {
        // We can not track more performance before installation or before PAGE init, sorry.
        return $info;
    }
    $filtermanager = filter_manager::instance();
    if (method_exists($filtermanager, 'get_performance_summary')) {
        list($filterinfo, $nicenames) = $filtermanager->get_performance_summary();
        $info = array_merge($filterinfo, $info);
        foreach ($filterinfo as $key => $value) {
            $info['html'] .= "<span class='{$key}'>{$nicenames[$key]}: {$value} </span> ";
            $info['txt'] .= "{$key}: {$value} ";
        }
    }
    $stringmanager = get_string_manager();
    if (method_exists($stringmanager, 'get_performance_summary')) {
        list($filterinfo, $nicenames) = $stringmanager->get_performance_summary();
        $info = array_merge($filterinfo, $info);
        foreach ($filterinfo as $key => $value) {
            $info['html'] .= "<span class='{$key}'>{$nicenames[$key]}: {$value} </span> ";
            $info['txt'] .= "{$key}: {$value} ";
        }
    }
    $jsmodules = $PAGE->requires->get_loaded_modules();
    if ($jsmodules) {
        $yuicount = 0;
        $othercount = 0;
        $details = '';
        foreach ($jsmodules as $module => $backtraces) {
            if (strpos($module, 'yui') === 0) {
                $yuicount += 1;
            } else {
                $othercount += 1;
            }
            if (!empty($CFG->yuimoduledebug)) {
                // Hidden feature for developers working on YUI module infrastructure.
                $details .= "<div class='yui-module'><p>{$module}</p>";
                foreach ($backtraces as $backtrace) {
                    $details .= "<div class='backtrace'>{$backtrace}</div>";
                }
                $details .= '</div>';
            }
        }
        $info['html'] .= "<span class='includedyuimodules'>Included YUI modules: {$yuicount}</span> ";
        $info['txt'] .= "includedyuimodules: {$yuicount} ";
        $info['html'] .= "<span class='includedjsmodules'>Other JavaScript modules: {$othercount}</span> ";
        $info['txt'] .= "includedjsmodules: {$othercount} ";
        if ($details) {
            $info['html'] .= '<div id="yui-module-debug" class="notifytiny">' . $details . '</div>';
        }
    }
    if (!empty($PERF->logwrites)) {
        $info['logwrites'] = $PERF->logwrites;
        $info['html'] .= '<span class="logwrites">Log DB writes ' . $info['logwrites'] . '</span> ';
        $info['txt'] .= 'logwrites: ' . $info['logwrites'] . ' ';
    }
    $info['dbqueries'] = $DB->perf_get_reads() . '/' . ($DB->perf_get_writes() - $PERF->logwrites);
    $info['html'] .= '<span class="dbqueries">DB reads/writes: ' . $info['dbqueries'] . '</span> ';
    $info['txt'] .= 'db reads/writes: ' . $info['dbqueries'] . ' ';
    if (function_exists('posix_times')) {
        $ptimes = posix_times();
        if (is_array($ptimes)) {
            foreach ($ptimes as $key => $val) {
                $info[$key] = $ptimes[$key] - $PERF->startposixtimes[$key];
            }
            $info['html'] .= "<span class=\"posixtimes\">ticks: {$info['ticks']} user: {$info['utime']} sys: {$info['stime']} cuser: {$info['cutime']} csys: {$info['cstime']}</span> ";
            $info['txt'] .= "ticks: {$info['ticks']} user: {$info['utime']} sys: {$info['stime']} cuser: {$info['cutime']} csys: {$info['cstime']} ";
        }
    }
    // Grab the load average for the last minute.
    // /proc will only work under some linux configurations
    // while uptime is there under MacOSX/Darwin and other unices.
    if (is_readable('/proc/loadavg') && ($loadavg = @file('/proc/loadavg'))) {
        list($serverload) = explode(' ', $loadavg[0]);
        unset($loadavg);
    } else {
        if (function_exists('is_executable') && is_executable('/usr/bin/uptime') && ($loadavg = `/usr/bin/uptime`)) {
            if (preg_match('/load averages?: (\\d+[\\.,:]\\d+)/', $loadavg, $matches)) {
                $serverload = $matches[1];
            } else {
                trigger_error('Could not parse uptime output!');
            }
        }
    }
    if (!empty($serverload)) {
        $info['serverload'] = $serverload;
        $info['html'] .= '<span class="serverload">Load average: ' . $info['serverload'] . '</span> ';
        $info['txt'] .= "serverload: {$info['serverload']} ";
    }
    // Display size of session if session started.
    if ($si = \core\session\manager::get_performance_info()) {
        $info['sessionsize'] = $si['size'];
        $info['html'] .= $si['html'];
        $info['txt'] .= $si['txt'];
    }
    if ($stats = cache_helper::get_stats()) {
        $html = '<span class="cachesused">';
        $html .= '<span class="cache-stats-heading">Caches used (hits/misses/sets)</span>';
        $text = 'Caches used (hits/misses/sets): ';
        $hits = 0;
        $misses = 0;
        $sets = 0;
        foreach ($stats as $definition => $stores) {
            $html .= '<span class="cache-definition-stats">';
            $html .= '<span class="cache-definition-stats-heading">' . $definition . '</span>';
            $text .= "{$definition} {";
            foreach ($stores as $store => $data) {
                $hits += $data['hits'];
                $misses += $data['misses'];
                $sets += $data['sets'];
                if ($data['hits'] == 0 and $data['misses'] > 0) {
                    $cachestoreclass = 'nohits';
                } else {
                    if ($data['hits'] < $data['misses']) {
                        $cachestoreclass = 'lowhits';
                    } else {
                        $cachestoreclass = 'hihits';
                    }
                }
                $text .= "{$store}({$data['hits']}/{$data['misses']}/{$data['sets']}) ";
                $html .= "<span class=\"cache-store-stats {$cachestoreclass}\">{$store}: {$data['hits']} / {$data['misses']} / {$data['sets']}</span>";
            }
            $html .= '</span>';
            $text .= '} ';
        }
        $html .= "<span class='cache-total-stats'>Total: {$hits} / {$misses} / {$sets}</span>";
        $html .= '</span> ';
        $info['cachesused'] = "{$hits} / {$misses} / {$sets}";
        $info['html'] .= $html;
        $info['txt'] .= $text . '. ';
    } else {
        $info['cachesused'] = '0 / 0 / 0';
        $info['html'] .= '<span class="cachesused">Caches used (hits/misses/sets): 0/0/0</span>';
        $info['txt'] .= 'Caches used (hits/misses/sets): 0/0/0 ';
    }
    $info['html'] = '<div class="performanceinfo siteinfo">' . $info['html'] . '</div>';
    return $info;
}
Example #13
0
 /**
  * Returns the site identifier.
  *
  * @return string
  */
 public static function get_site_identifier()
 {
     global $CFG;
     if (!is_null(self::$siteidentifier)) {
         return self::$siteidentifier;
     }
     // If site identifier hasn't been collected yet attempt to get it from the cache config.
     $factory = cache_factory::instance();
     // If the factory is initialising then we don't want to try to get it from the config or we risk
     // causing the cache to enter an infinite initialisation loop.
     if (!$factory->is_initialising()) {
         $config = $factory->create_config_instance();
         self::$siteidentifier = $config->get_site_identifier();
     }
     if (is_null(self::$siteidentifier)) {
         // If the site identifier is still null then config isn't aware of it yet.
         // We'll see if the CFG is loaded, and if not we will just use unknown.
         // It's very important here that we don't use get_config. We don't want an endless cache loop!
         if (!empty($CFG->siteidentifier)) {
             self::$siteidentifier = self::update_site_identifier($CFG->siteidentifier);
         } else {
             // It's not being recorded in MUC's config and the config data hasn't been loaded yet.
             // Likely we are initialising.
             return 'unknown';
         }
     }
     return self::$siteidentifier;
 }
Example #14
0
            }
            $newgroup = new stdClass();
            $newgroup->courseid = $data->courseid;
            $newgroup->name = $group['name'];
            $groupid = groups_create_group($newgroup);
            $createdgroups[] = $groupid;
            foreach ($group['members'] as $user) {
                groups_add_member($groupid, $user->id);
            }
            if ($grouping) {
                // Ask this function not to invalidate the cache, we'll do that manually once at the end.
                groups_assign_grouping($grouping->id, $groupid, null, false);
            }
        }
        // Invalidate the course groups cache seeing as we've changed it.
        cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
        if ($failed) {
            foreach ($createdgroups as $groupid) {
                groups_delete_group($groupid);
            }
            if ($createdgrouping) {
                groups_delete_grouping($createdgrouping);
            }
        } else {
            redirect($returnurl);
        }
    }
}
$PAGE->navbar->add($strparticipants, new moodle_url('/user/index.php', array('id' => $courseid)));
$PAGE->navbar->add($strgroups, new moodle_url('/group/index.php', array('id' => $courseid)));
$PAGE->navbar->add($strautocreategroups);
Example #15
0
 /**
  * Common public method to create a cache instance given a definition.
  *
  * This is used by the static make methods.
  *
  * @param cache_definition $definition
  * @return cache_application|cache_session|cache_store
  * @throws coding_exception
  */
 public function create_cache(cache_definition $definition)
 {
     $class = $definition->get_cache_class();
     $stores = cache_helper::get_stores_suitable_for_definition($definition);
     foreach ($stores as $key => $store) {
         if (!$store::are_requirements_met()) {
             unset($stores[$key]);
         }
     }
     if (count($stores) === 0) {
         // Hmm still no stores, better provide a dummy store to mimic functionality. The dev will be none the wiser.
         $stores[] = $this->create_dummy_store($definition);
     }
     $loader = null;
     if ($definition->has_data_source()) {
         $loader = $definition->get_data_source();
     }
     while (($store = array_pop($stores)) !== null) {
         $loader = new $class($definition, $store, $loader);
     }
     return $loader;
 }
Example #16
0
/**
 * get_performance_info() pairs up with init_performance_info()
 * loaded in setup.php. Returns an array with 'html' and 'txt'
 * values ready for use, and each of the individual stats provided
 * separately as well.
 *
 * @return array
 */
function get_performance_info()
{
    global $CFG, $PERF, $DB, $PAGE;
    $info = array();
    $info['txt'] = me() . ' ';
    // Holds log-friendly representation.
    $info['html'] = '';
    if (!empty($CFG->themedesignermode)) {
        // Attempt to avoid devs debugging peformance issues, when its caused by css building and so on.
        $info['html'] .= '<p><strong>Warning: Theme designer mode is enabled.</strong></p>';
    }
    $info['html'] .= '<ul class="list-unstyled m-l-1">';
    // Holds userfriendly HTML representation.
    $info['realtime'] = microtime_diff($PERF->starttime, microtime());
    $info['html'] .= '<li class="timeused">' . $info['realtime'] . ' secs</li> ';
    $info['txt'] .= 'time: ' . $info['realtime'] . 's ';
    if (function_exists('memory_get_usage')) {
        $info['memory_total'] = memory_get_usage();
        $info['memory_growth'] = memory_get_usage() - $PERF->startmemory;
        $info['html'] .= '<li class="memoryused">RAM: ' . display_size($info['memory_total']) . '</li> ';
        $info['txt'] .= 'memory_total: ' . $info['memory_total'] . 'B (' . display_size($info['memory_total']) . ') memory_growth: ' . $info['memory_growth'] . 'B (' . display_size($info['memory_growth']) . ') ';
    }
    if (function_exists('memory_get_peak_usage')) {
        $info['memory_peak'] = memory_get_peak_usage();
        $info['html'] .= '<li class="memoryused">RAM peak: ' . display_size($info['memory_peak']) . '</li> ';
        $info['txt'] .= 'memory_peak: ' . $info['memory_peak'] . 'B (' . display_size($info['memory_peak']) . ') ';
    }
    $inc = get_included_files();
    $info['includecount'] = count($inc);
    $info['html'] .= '<li class="included">Included ' . $info['includecount'] . ' files</li> ';
    $info['txt'] .= 'includecount: ' . $info['includecount'] . ' ';
    if (!empty($CFG->early_install_lang) or empty($PAGE)) {
        // We can not track more performance before installation or before PAGE init, sorry.
        return $info;
    }
    $filtermanager = filter_manager::instance();
    if (method_exists($filtermanager, 'get_performance_summary')) {
        list($filterinfo, $nicenames) = $filtermanager->get_performance_summary();
        $info = array_merge($filterinfo, $info);
        foreach ($filterinfo as $key => $value) {
            $info['html'] .= "<li class='{$key}'>{$nicenames[$key]}: {$value} </li> ";
            $info['txt'] .= "{$key}: {$value} ";
        }
    }
    $stringmanager = get_string_manager();
    if (method_exists($stringmanager, 'get_performance_summary')) {
        list($filterinfo, $nicenames) = $stringmanager->get_performance_summary();
        $info = array_merge($filterinfo, $info);
        foreach ($filterinfo as $key => $value) {
            $info['html'] .= "<li class='{$key}'>{$nicenames[$key]}: {$value} </li> ";
            $info['txt'] .= "{$key}: {$value} ";
        }
    }
    if (!empty($PERF->logwrites)) {
        $info['logwrites'] = $PERF->logwrites;
        $info['html'] .= '<li class="logwrites">Log DB writes ' . $info['logwrites'] . '</li> ';
        $info['txt'] .= 'logwrites: ' . $info['logwrites'] . ' ';
    }
    $info['dbqueries'] = $DB->perf_get_reads() . '/' . ($DB->perf_get_writes() - $PERF->logwrites);
    $info['html'] .= '<li class="dbqueries">DB reads/writes: ' . $info['dbqueries'] . '</li> ';
    $info['txt'] .= 'db reads/writes: ' . $info['dbqueries'] . ' ';
    $info['dbtime'] = round($DB->perf_get_queries_time(), 5);
    $info['html'] .= '<li class="dbtime">DB queries time: ' . $info['dbtime'] . ' secs</li> ';
    $info['txt'] .= 'db queries time: ' . $info['dbtime'] . 's ';
    if (function_exists('posix_times')) {
        $ptimes = posix_times();
        if (is_array($ptimes)) {
            foreach ($ptimes as $key => $val) {
                $info[$key] = $ptimes[$key] - $PERF->startposixtimes[$key];
            }
            $info['html'] .= "<li class=\"posixtimes\">ticks: {$info['ticks']} user: {$info['utime']} sys: {$info['stime']} cuser: {$info['cutime']} csys: {$info['cstime']}</li> ";
            $info['txt'] .= "ticks: {$info['ticks']} user: {$info['utime']} sys: {$info['stime']} cuser: {$info['cutime']} csys: {$info['cstime']} ";
        }
    }
    // Grab the load average for the last minute.
    // /proc will only work under some linux configurations
    // while uptime is there under MacOSX/Darwin and other unices.
    if (is_readable('/proc/loadavg') && ($loadavg = @file('/proc/loadavg'))) {
        list($serverload) = explode(' ', $loadavg[0]);
        unset($loadavg);
    } else {
        if (function_exists('is_executable') && is_executable('/usr/bin/uptime') && ($loadavg = `/usr/bin/uptime`)) {
            if (preg_match('/load averages?: (\\d+[\\.,:]\\d+)/', $loadavg, $matches)) {
                $serverload = $matches[1];
            } else {
                trigger_error('Could not parse uptime output!');
            }
        }
    }
    if (!empty($serverload)) {
        $info['serverload'] = $serverload;
        $info['html'] .= '<li class="serverload">Load average: ' . $info['serverload'] . '</li> ';
        $info['txt'] .= "serverload: {$info['serverload']} ";
    }
    // Display size of session if session started.
    if ($si = \core\session\manager::get_performance_info()) {
        $info['sessionsize'] = $si['size'];
        $info['html'] .= $si['html'];
        $info['txt'] .= $si['txt'];
    }
    if ($stats = cache_helper::get_stats()) {
        $html = '<ul class="cachesused list-unstyled m-l-1">';
        $html .= '<li class="cache-stats-heading">Caches used (hits/misses/sets)</li>';
        $text = 'Caches used (hits/misses/sets): ';
        $hits = 0;
        $misses = 0;
        $sets = 0;
        foreach ($stats as $definition => $details) {
            switch ($details['mode']) {
                case cache_store::MODE_APPLICATION:
                    $modeclass = 'application';
                    $mode = ' <span title="application cache">[a]</span>';
                    break;
                case cache_store::MODE_SESSION:
                    $modeclass = 'session';
                    $mode = ' <span title="session cache">[s]</span>';
                    break;
                case cache_store::MODE_REQUEST:
                    $modeclass = 'request';
                    $mode = ' <span title="request cache">[r]</span>';
                    break;
            }
            $html .= '<ul class="cache-definition-stats list-unstyled m-l-1 cache-mode-' . $modeclass . '">';
            $html .= '<li class="cache-definition-stats-heading p-t-1">' . $definition . $mode . '</li>';
            $text .= "{$definition} {";
            foreach ($details['stores'] as $store => $data) {
                $hits += $data['hits'];
                $misses += $data['misses'];
                $sets += $data['sets'];
                if ($data['hits'] == 0 and $data['misses'] > 0) {
                    $cachestoreclass = 'nohits text-danger';
                } else {
                    if ($data['hits'] < $data['misses']) {
                        $cachestoreclass = 'lowhits text-warning';
                    } else {
                        $cachestoreclass = 'hihits text-success';
                    }
                }
                $text .= "{$store}({$data['hits']}/{$data['misses']}/{$data['sets']}) ";
                $html .= "<li class=\"cache-store-stats {$cachestoreclass}\">{$store}: {$data['hits']} / {$data['misses']} / {$data['sets']}</li>";
            }
            $html .= '</ul>';
            $text .= '} ';
        }
        $html .= '</ul> ';
        $html .= "<div class='cache-total-stats row'>Total: {$hits} / {$misses} / {$sets}</div>";
        $info['cachesused'] = "{$hits} / {$misses} / {$sets}";
        $info['html'] .= $html;
        $info['txt'] .= $text . '. ';
    } else {
        $info['cachesused'] = '0 / 0 / 0';
        $info['html'] .= '<div class="cachesused">Caches used (hits/misses/sets): 0/0/0</div>';
        $info['txt'] .= 'Caches used (hits/misses/sets): 0/0/0 ';
    }
    $info['html'] = '<div class="performanceinfo siteinfo">' . $info['html'] . '</div>';
    return $info;
}
Example #17
0
     $factory = cache_factory::instance();
     $definition = $factory->create_definition($component, $area);
     if ($definition->has_required_identifiers()) {
         // We will have to purge the stores used by this definition.
         cache_helper::purge_stores_used_by_definition($component, $area);
     } else {
         // Alrighty we can purge just the data belonging to this definition.
         cache_helper::purge_by_definition($component, $area);
     }
     redirect($PAGE->url, get_string('purgedefinitionsuccess', 'cache'), 5);
     break;
 case 'purgestore':
 case 'purge':
     // Purge a store cache.
     $store = required_param('store', PARAM_TEXT);
     cache_helper::purge_store($store);
     redirect($PAGE->url, get_string('purgestoresuccess', 'cache'), 5);
     break;
 case 'newlockinstance':
     // Adds a new lock instance.
     $lock = required_param('lock', PARAM_ALPHANUMEXT);
     $mform = cache_administration_helper::get_add_lock_form($lock);
     if ($mform->is_cancelled()) {
         redirect($PAGE->url);
     } else {
         if ($data = $mform->get_data()) {
             $factory = cache_factory::instance();
             $config = $factory->create_config_instance(true);
             $name = $data->name;
             $data = cache_administration_helper::get_lock_configuration_from_data($lock, $data);
             $config->add_lock_instance($name, $lock, $data);
Example #18
0
/**
 * Delete subscription and all related events.
 *
 * @param int|stdClass $subscription subscription or it's id, which needs to be deleted.
 */
function calendar_delete_subscription($subscription)
{
    global $DB;
    if (!is_object($subscription)) {
        $subscription = $DB->get_record('event_subscriptions', array('id' => $subscription), '*', MUST_EXIST);
    }
    // Delete subscription and related events.
    $DB->delete_records('event', array('subscriptionid' => $subscription->id));
    $DB->delete_records('event_subscriptions', array('id' => $subscription->id));
    cache_helper::invalidate_by_definition('core', 'calendar_subscriptions', array(), array($subscription->id));
    // Trigger event, calendar subscription deleted.
    $eventparams = array('objectid' => $subscription->id, 'context' => calendar_get_calendar_context($subscription), 'other' => array('courseid' => $subscription->courseid));
    $event = \core\event\calendar_subscription_deleted::create($eventparams);
    $event->trigger();
}
Example #19
0
/**
 * Delete subscription and all related events.
 *
 * @param int|stdClass $subscription subscription or it's id, which needs to be deleted.
 */
function calendar_delete_subscription($subscription)
{
    global $DB;
    if (is_object($subscription)) {
        $subscription = $subscription->id;
    }
    // Delete subscription and related events.
    $DB->delete_records('event', array('subscriptionid' => $subscription));
    $DB->delete_records('event_subscriptions', array('id' => $subscription));
    cache_helper::invalidate_by_definition('core', 'calendar_subscriptions', array(), array($subscription));
}
Example #20
0
/**
 * get_performance_info() pairs up with init_performance_info()
 * loaded in setup.php. Returns an array with 'html' and 'txt'
 * values ready for use, and each of the individual stats provided
 * separately as well.
 *
 * @return array
 */
function get_performance_info() {
    global $CFG, $PERF, $DB, $PAGE;

    $info = array();
    $info['html'] = '';         // Holds userfriendly HTML representation.
    $info['txt']  = me() . ' '; // Holds log-friendly representation.

    $info['realtime'] = microtime_diff($PERF->starttime, microtime());

    $info['html'] .= '<span class="timeused">'.$info['realtime'].' secs</span> ';
    $info['txt'] .= 'time: '.$info['realtime'].'s ';

    if (function_exists('memory_get_usage')) {
        $info['memory_total'] = memory_get_usage();
        $info['memory_growth'] = memory_get_usage() - $PERF->startmemory;
        $info['html'] .= '<span class="memoryused">RAM: '.display_size($info['memory_total']).'</span> ';
        $info['txt']  .= 'memory_total: '.$info['memory_total'].'B (' . display_size($info['memory_total']).') memory_growth: '.
            $info['memory_growth'].'B ('.display_size($info['memory_growth']).') ';
    }

    if (function_exists('memory_get_peak_usage')) {
        $info['memory_peak'] = memory_get_peak_usage();
        $info['html'] .= '<span class="memoryused">RAM peak: '.display_size($info['memory_peak']).'</span> ';
        $info['txt']  .= 'memory_peak: '.$info['memory_peak'].'B (' . display_size($info['memory_peak']).') ';
    }

    $inc = get_included_files();
    $info['includecount'] = count($inc);
    $info['html'] .= '<span class="included">Included '.$info['includecount'].' files</span> ';
    $info['txt']  .= 'includecount: '.$info['includecount'].' ';

    if (!empty($CFG->early_install_lang) or empty($PAGE)) {
        // We can not track more performance before installation or before PAGE init, sorry.
        return $info;
    }

    $filtermanager = filter_manager::instance();
    if (method_exists($filtermanager, 'get_performance_summary')) {
        list($filterinfo, $nicenames) = $filtermanager->get_performance_summary();
        $info = array_merge($filterinfo, $info);
        foreach ($filterinfo as $key => $value) {
            $info['html'] .= "<span class='$key'>$nicenames[$key]: $value </span> ";
            $info['txt'] .= "$key: $value ";
        }
    }

    $stringmanager = get_string_manager();
    if (method_exists($stringmanager, 'get_performance_summary')) {
        list($filterinfo, $nicenames) = $stringmanager->get_performance_summary();
        $info = array_merge($filterinfo, $info);
        foreach ($filterinfo as $key => $value) {
            $info['html'] .= "<span class='$key'>$nicenames[$key]: $value </span> ";
            $info['txt'] .= "$key: $value ";
        }
    }

    if (!empty($PERF->logwrites)) {
        $info['logwrites'] = $PERF->logwrites;
        $info['html'] .= '<span class="logwrites">Log DB writes '.$info['logwrites'].'</span> ';
        $info['txt'] .= 'logwrites: '.$info['logwrites'].' ';
    }

    $info['dbqueries'] = $DB->perf_get_reads().'/'.($DB->perf_get_writes() - $PERF->logwrites);
    $info['html'] .= '<span class="dbqueries">DB reads/writes: '.$info['dbqueries'].'</span> ';
    $info['txt'] .= 'db reads/writes: '.$info['dbqueries'].' ';

    $info['dbtime'] = round($DB->perf_get_queries_time(), 5);
    $info['html'] .= '<span class="dbtime">DB queries time: '.$info['dbtime'].' secs</span> ';
    $info['txt'] .= 'db queries time: ' . $info['dbtime'] . 's ';

    if (function_exists('posix_times')) {
        $ptimes = posix_times();
        if (is_array($ptimes)) {
            foreach ($ptimes as $key => $val) {
                $info[$key] = $ptimes[$key] -  $PERF->startposixtimes[$key];
            }
            $info['html'] .= "<span class=\"posixtimes\">ticks: $info[ticks] user: $info[utime] sys: $info[stime] cuser: $info[cutime] csys: $info[cstime]</span> ";
            $info['txt'] .= "ticks: $info[ticks] user: $info[utime] sys: $info[stime] cuser: $info[cutime] csys: $info[cstime] ";
        }
    }

    // Grab the load average for the last minute.
    // /proc will only work under some linux configurations
    // while uptime is there under MacOSX/Darwin and other unices.
    if (is_readable('/proc/loadavg') && $loadavg = @file('/proc/loadavg')) {
        list($serverload) = explode(' ', $loadavg[0]);
        unset($loadavg);
    } else if ( function_exists('is_executable') && is_executable('/usr/bin/uptime') && $loadavg = `/usr/bin/uptime` ) {
        if (preg_match('/load averages?: (\d+[\.,:]\d+)/', $loadavg, $matches)) {
            $serverload = $matches[1];
        } else {
            trigger_error('Could not parse uptime output!');
        }
    }
    if (!empty($serverload)) {
        $info['serverload'] = $serverload;
        $info['html'] .= '<span class="serverload">Load average: '.$info['serverload'].'</span> ';
        $info['txt'] .= "serverload: {$info['serverload']} ";
    }

    // Display size of session if session started.
    if ($si = \core\session\manager::get_performance_info()) {
        $info['sessionsize'] = $si['size'];
        $info['html'] .= $si['html'];
        $info['txt'] .= $si['txt'];
    }

    if ($stats = cache_helper::get_stats()) {
        $html = '<span class="cachesused">';
        $html .= '<span class="cache-stats-heading">Caches used (hits/misses/sets)</span>';
        $text = 'Caches used (hits/misses/sets): ';
        $hits = 0;
        $misses = 0;
        $sets = 0;
        foreach ($stats as $definition => $stores) {
            $html .= '<span class="cache-definition-stats">';
            $html .= '<span class="cache-definition-stats-heading">'.$definition.'</span>';
            $text .= "$definition {";
            foreach ($stores as $store => $data) {
                $hits += $data['hits'];
                $misses += $data['misses'];
                $sets += $data['sets'];
                if ($data['hits'] == 0 and $data['misses'] > 0) {
                    $cachestoreclass = 'nohits';
                } else if ($data['hits'] < $data['misses']) {
                    $cachestoreclass = 'lowhits';
                } else {
                    $cachestoreclass = 'hihits';
                }
                $text .= "$store($data[hits]/$data[misses]/$data[sets]) ";
                $html .= "<span class=\"cache-store-stats $cachestoreclass\">$store: $data[hits] / $data[misses] / $data[sets]</span>";
            }
            $html .= '</span>';
            $text .= '} ';
        }
        $html .= "<span class='cache-total-stats'>Total: $hits / $misses / $sets</span>";
        $html .= '</span> ';
        $info['cachesused'] = "$hits / $misses / $sets";
        $info['html'] .= $html;
        $info['txt'] .= $text.'. ';
    } else {
        $info['cachesused'] = '0 / 0 / 0';
        $info['html'] .= '<span class="cachesused">Caches used (hits/misses/sets): 0/0/0</span>';
        $info['txt'] .= 'Caches used (hits/misses/sets): 0/0/0 ';
    }

    $info['html'] = '<div class="performanceinfo siteinfo">'.$info['html'].'</div>';
    return $info;
}
Example #21
0
 /**
  * Common public method to create a cache instance given a definition.
  *
  * This is used by the static make methods.
  *
  * @param cache_definition $definition
  * @return cache_application|cache_session|cache_store
  * @throws coding_exception
  */
 public function create_cache(cache_definition $definition)
 {
     $class = $definition->get_cache_class();
     if ($this->is_initialising()) {
         // Do nothing we just want the dummy store.
         $stores = array();
     } else {
         $stores = cache_helper::get_cache_stores($definition);
     }
     if (count($stores) === 0) {
         // Hmm no stores, better provide a dummy store to mimick functionality. The dev will be none the wiser.
         $stores[] = $this->create_dummy_store($definition);
     }
     $loader = null;
     if ($definition->has_data_source()) {
         $loader = $definition->get_data_source();
     }
     while (($store = array_pop($stores)) !== null) {
         $loader = new $class($definition, $store, $loader);
     }
     return $loader;
 }
 /**
  * Returns an array about the definitions. All the information a renderer needs.
  * @return array
  */
 public static function get_definition_summaries()
 {
     $instance = cache_config::instance();
     $definitions = $instance->get_definitions();
     $storenames = array();
     foreach ($instance->get_all_stores() as $key => $store) {
         if (!empty($store['default'])) {
             $storenames[$key] = new lang_string('store_' . $key, 'cache');
         }
     }
     $modemappings = array();
     foreach ($instance->get_mode_mappings() as $mapping) {
         $mode = $mapping['mode'];
         if (!array_key_exists($mode, $modemappings)) {
             $modemappings[$mode] = array();
         }
         if (array_key_exists($mapping['store'], $storenames)) {
             $modemappings[$mode][] = $storenames[$mapping['store']];
         } else {
             $modemappings[$mode][] = $mapping['store'];
         }
     }
     $definitionmappings = array();
     foreach ($instance->get_definition_mappings() as $mapping) {
         $definition = $mapping['definition'];
         if (!array_key_exists($definition, $definitionmappings)) {
             $definitionmappings[$definition] = array();
         }
         if (array_key_exists($mapping['store'], $storenames)) {
             $definitionmappings[$definition][] = $storenames[$mapping['store']];
         } else {
             $definitionmappings[$definition][] = $mapping['store'];
         }
     }
     $return = array();
     foreach ($definitions as $id => $definition) {
         $mappings = array();
         if (array_key_exists($id, $definitionmappings)) {
             $mappings = $definitionmappings[$id];
         } else {
             if (empty($definition['mappingsonly'])) {
                 $mappings = $modemappings[$definition['mode']];
             }
         }
         $return[$id] = array('id' => $id, 'name' => cache_helper::get_definition_name($definition), 'mode' => $definition['mode'], 'component' => $definition['component'], 'area' => $definition['area'], 'mappings' => $mappings, 'sharingoptions' => self::get_definition_sharing_options($definition['sharingoptions'], false), 'selectedsharingoption' => self::get_definition_sharing_options($definition['selectedsharingoption'], true), 'userinputsharingkey' => $definition['userinputsharingkey']);
     }
     return $return;
 }
Example #23
0
 /**
  * Stores the valid fetched response for later usage
  *
  * This implementation uses the config_plugins table as the permanent storage.
  *
  * @param string $response raw valid data returned by {@link self::get_response()}
  */
 protected function store_response($response)
 {
     set_config('recentfetch', time(), 'core_plugin');
     set_config('recentresponse', $response, 'core_plugin');
     if (defined('CACHE_DISABLE_ALL') and CACHE_DISABLE_ALL) {
         // Very nasty hack to work around cache coherency issues on admin/index.php?cache=0 page,
         // we definitely need to keep caches in sync when writing into DB at all times!
         cache_helper::purge_all(true);
     }
     $this->restore_response(true);
 }
Example #24
0
 /**
  * Loads the configuration file and parses its contents into the expected structure.
  *
  * @param array|false $configuration Can be used to force a configuration. Should only be used when truly required.
  * @return boolean
  */
 public function load($configuration = false)
 {
     global $CFG;
     if ($configuration === false) {
         $configuration = $this->include_configuration();
     }
     $this->configstores = array();
     $this->configdefinitions = array();
     $this->configlocks = array();
     $this->configmodemappings = array();
     $this->configdefinitionmappings = array();
     $this->configlockmappings = array();
     $siteidentifier = 'unknown';
     if (array_key_exists('siteidentifier', $configuration)) {
         $siteidentifier = $configuration['siteidentifier'];
     }
     $this->siteidentifier = $siteidentifier;
     // Filter the lock instances.
     $defaultlock = null;
     foreach ($configuration['locks'] as $conf) {
         if (!is_array($conf)) {
             // Something is very wrong here.
             continue;
         }
         if (!array_key_exists('name', $conf)) {
             // Not a valid definition configuration.
             continue;
         }
         $name = $conf['name'];
         if (array_key_exists($name, $this->configlocks)) {
             debugging('Duplicate cache lock detected. This should never happen.', DEBUG_DEVELOPER);
             continue;
         }
         $conf['default'] = !empty($conf['default']);
         if ($defaultlock === null || $conf['default']) {
             $defaultlock = $name;
         }
         $this->configlocks[$name] = $conf;
     }
     // Filter the stores.
     $availableplugins = cache_helper::early_get_cache_plugins();
     foreach ($configuration['stores'] as $store) {
         if (!is_array($store) || !array_key_exists('name', $store) || !array_key_exists('plugin', $store)) {
             // Not a valid instance configuration.
             debugging('Invalid cache store in config. Missing name or plugin.', DEBUG_DEVELOPER);
             continue;
         }
         $plugin = $store['plugin'];
         $class = 'cachestore_' . $plugin;
         $exists = array_key_exists($plugin, $availableplugins);
         if (!$exists) {
             // Not a valid plugin, or has been uninstalled, just skip it an carry on.
             debugging('Invalid cache store in config. Not an available plugin.', DEBUG_DEVELOPER);
             continue;
         }
         $file = $CFG->dirroot . '/cache/stores/' . $plugin . '/lib.php';
         if (!class_exists($class) && file_exists($file)) {
             require_once $file;
         }
         if (!class_exists($class)) {
             continue;
         }
         if (!array_key_exists('cache_store', class_parents($class))) {
             continue;
         }
         if (!array_key_exists('configuration', $store) || !is_array($store['configuration'])) {
             $store['configuration'] = array();
         }
         $store['class'] = $class;
         $store['default'] = !empty($store['default']);
         if (!array_key_exists('lock', $store) || !array_key_exists($store['lock'], $this->configlocks)) {
             $store['lock'] = $defaultlock;
         }
         $this->configstores[$store['name']] = $store;
     }
     // Filter the definitions.
     foreach ($configuration['definitions'] as $id => $conf) {
         if (!is_array($conf)) {
             // Something is very wrong here.
             continue;
         }
         if (!array_key_exists('mode', $conf) || !array_key_exists('component', $conf) || !array_key_exists('area', $conf)) {
             // Not a valid definition configuration.
             continue;
         }
         if (array_key_exists($id, $this->configdefinitions)) {
             debugging('Duplicate cache definition detected. This should never happen.', DEBUG_DEVELOPER);
             continue;
         }
         $conf['mode'] = (int) $conf['mode'];
         if ($conf['mode'] < cache_store::MODE_APPLICATION || $conf['mode'] > cache_store::MODE_REQUEST) {
             // Invalid cache mode used for the definition.
             continue;
         }
         $this->configdefinitions[$id] = $conf;
     }
     // Filter the mode mappings.
     foreach ($configuration['modemappings'] as $mapping) {
         if (!is_array($mapping) || !array_key_exists('mode', $mapping) || !array_key_exists('store', $mapping)) {
             // Not a valid mapping configuration.
             debugging('A cache mode mapping entry is invalid.', DEBUG_DEVELOPER);
             continue;
         }
         if (!array_key_exists($mapping['store'], $this->configstores)) {
             // Mapped array instance doesn't exist.
             debugging('A cache mode mapping exists for a mode or store that does not exist.', DEBUG_DEVELOPER);
             continue;
         }
         $mapping['mode'] = (int) $mapping['mode'];
         if ($mapping['mode'] < 0 || $mapping['mode'] > 4) {
             // Invalid cache type used for the mapping.
             continue;
         }
         if (!array_key_exists('sort', $mapping)) {
             $mapping['sort'] = 0;
         }
         $this->configmodemappings[] = $mapping;
     }
     // Filter the definition mappings.
     foreach ($configuration['definitionmappings'] as $mapping) {
         if (!is_array($mapping) || !array_key_exists('definition', $mapping) || !array_key_exists('store', $mapping)) {
             // Not a valid mapping configuration.
             continue;
         }
         if (!array_key_exists($mapping['store'], $this->configstores)) {
             // Mapped array instance doesn't exist.
             continue;
         }
         if (!array_key_exists($mapping['definition'], $this->configdefinitions)) {
             // Mapped array instance doesn't exist.
             continue;
         }
         if (!array_key_exists('sort', $mapping)) {
             $mapping['sort'] = 0;
         }
         $this->configdefinitionmappings[] = $mapping;
     }
     usort($this->configmodemappings, array($this, 'sort_mappings'));
     usort($this->configdefinitionmappings, array($this, 'sort_mappings'));
     return true;
 }
Example #25
0
 /**
  * Returns the site identifier.
  *
  * @return string
  */
 public static function get_site_identifier()
 {
     if (is_null(self::$siteidentifier)) {
         $factory = cache_factory::instance();
         $config = $factory->create_config_instance();
         self::$siteidentifier = $config->get_site_identifier();
     }
     return self::$siteidentifier;
 }
Example #26
0
/**
 * Upgrade/install other parts of moodle
 * @param bool $verbose
 * @return void, may throw exception
 */
function upgrade_noncore($verbose) {
    global $CFG;

    raise_memory_limit(MEMORY_EXTRA);

    // upgrade all plugins types
    try {
        // Reset caches before any output.
        cache_helper::purge_all(true);
        purge_all_caches();

        $plugintypes = core_component::get_plugin_types();
        foreach ($plugintypes as $type=>$location) {
            upgrade_plugins($type, 'print_upgrade_part_start', 'print_upgrade_part_end', $verbose);
        }
        // Update cache definitions. Involves scanning each plugin for any changes.
        cache_helper::update_definitions();
        // Mark the site as upgraded.
        set_config('allversionshash', core_component::get_all_versions_hash());

        // Purge caches again, just to be sure we arn't holding onto old stuff now.
        cache_helper::purge_all(true);
        purge_all_caches();

    } catch (Exception $ex) {
        upgrade_handle_exception($ex);
    }
}
Example #27
0
 protected function after_execute()
 {
     // Add group related files, matching with "group" mappings
     $this->add_related_files('group', 'icon', 'group');
     $this->add_related_files('group', 'description', 'group');
     // Add grouping related files, matching with "grouping" mappings
     $this->add_related_files('grouping', 'description', 'grouping');
     // Invalidate the course group data.
     cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($this->get_courseid()));
 }
Example #28
0
/**
 * Fixes course category and course sortorder, also verifies category and course parents and paths.
 * (circular references are not fixed)
 *
 * @global object
 * @global object
 * @uses MAX_COURSES_IN_CATEGORY
 * @uses MAX_COURSE_CATEGORIES
 * @uses SITEID
 * @uses CONTEXT_COURSE
 * @return void
 */
function fix_course_sortorder()
{
    global $DB, $SITE;
    //WARNING: this is PHP5 only code!
    // if there are any changes made to courses or categories we will trigger
    // the cache events to purge all cached courses/categories data
    $cacheevents = array();
    if ($unsorted = $DB->get_records('course_categories', array('sortorder' => 0))) {
        //move all categories that are not sorted yet to the end
        $DB->set_field('course_categories', 'sortorder', MAX_COURSES_IN_CATEGORY * MAX_COURSE_CATEGORIES, array('sortorder' => 0));
        $cacheevents['changesincoursecat'] = true;
    }
    $allcats = $DB->get_records('course_categories', null, 'sortorder, id', 'id, sortorder, parent, depth, path');
    $topcats = array();
    $brokencats = array();
    foreach ($allcats as $cat) {
        $sortorder = (int) $cat->sortorder;
        if (!$cat->parent) {
            while (isset($topcats[$sortorder])) {
                $sortorder++;
            }
            $topcats[$sortorder] = $cat;
            continue;
        }
        if (!isset($allcats[$cat->parent])) {
            $brokencats[] = $cat;
            continue;
        }
        if (!isset($allcats[$cat->parent]->children)) {
            $allcats[$cat->parent]->children = array();
        }
        while (isset($allcats[$cat->parent]->children[$sortorder])) {
            $sortorder++;
        }
        $allcats[$cat->parent]->children[$sortorder] = $cat;
    }
    unset($allcats);
    // add broken cats to category tree
    if ($brokencats) {
        $defaultcat = reset($topcats);
        foreach ($brokencats as $cat) {
            $topcats[] = $cat;
        }
    }
    // now walk recursively the tree and fix any problems found
    $sortorder = 0;
    $fixcontexts = array();
    if (_fix_course_cats($topcats, $sortorder, 0, 0, '', $fixcontexts)) {
        $cacheevents['changesincoursecat'] = true;
    }
    // detect if there are "multiple" frontpage courses and fix them if needed
    $frontcourses = $DB->get_records('course', array('category' => 0), 'id');
    if (count($frontcourses) > 1) {
        if (isset($frontcourses[SITEID])) {
            $frontcourse = $frontcourses[SITEID];
            unset($frontcourses[SITEID]);
        } else {
            $frontcourse = array_shift($frontcourses);
        }
        $defaultcat = reset($topcats);
        foreach ($frontcourses as $course) {
            $DB->set_field('course', 'category', $defaultcat->id, array('id' => $course->id));
            $context = context_course::instance($course->id);
            $fixcontexts[$context->id] = $context;
            $cacheevents['changesincourse'] = true;
        }
        unset($frontcourses);
    } else {
        $frontcourse = reset($frontcourses);
    }
    // now fix the paths and depths in context table if needed
    if ($fixcontexts) {
        foreach ($fixcontexts as $fixcontext) {
            $fixcontext->reset_paths(false);
        }
        context_helper::build_all_paths(false);
        unset($fixcontexts);
        $cacheevents['changesincourse'] = true;
        $cacheevents['changesincoursecat'] = true;
    }
    // release memory
    unset($topcats);
    unset($brokencats);
    unset($fixcontexts);
    // fix frontpage course sortorder
    if ($frontcourse->sortorder != 1) {
        $DB->set_field('course', 'sortorder', 1, array('id' => $frontcourse->id));
        $cacheevents['changesincourse'] = true;
    }
    // now fix the course counts in category records if needed
    $sql = "SELECT cc.id, cc.coursecount, COUNT(c.id) AS newcount\n              FROM {course_categories} cc\n              LEFT JOIN {course} c ON c.category = cc.id\n          GROUP BY cc.id, cc.coursecount\n            HAVING cc.coursecount <> COUNT(c.id)";
    if ($updatecounts = $DB->get_records_sql($sql)) {
        // categories with more courses than MAX_COURSES_IN_CATEGORY
        $categories = array();
        foreach ($updatecounts as $cat) {
            $cat->coursecount = $cat->newcount;
            if ($cat->coursecount >= MAX_COURSES_IN_CATEGORY) {
                $categories[] = $cat->id;
            }
            unset($cat->newcount);
            $DB->update_record_raw('course_categories', $cat, true);
        }
        if (!empty($categories)) {
            $str = implode(', ', $categories);
            debugging("The number of courses (category id: {$str}) has reached MAX_COURSES_IN_CATEGORY (" . MAX_COURSES_IN_CATEGORY . "), it will cause a sorting performance issue, please increase the value of MAX_COURSES_IN_CATEGORY in lib/datalib.php file. See tracker issue: MDL-25669", DEBUG_DEVELOPER);
        }
        $cacheevents['changesincoursecat'] = true;
    }
    // now make sure that sortorders in course table are withing the category sortorder ranges
    $sql = "SELECT DISTINCT cc.id, cc.sortorder\n              FROM {course_categories} cc\n              JOIN {course} c ON c.category = cc.id\n             WHERE c.sortorder < cc.sortorder OR c.sortorder > cc.sortorder + " . MAX_COURSES_IN_CATEGORY;
    if ($fixcategories = $DB->get_records_sql($sql)) {
        //fix the course sortorder ranges
        foreach ($fixcategories as $cat) {
            $sql = "UPDATE {course}\n                       SET sortorder = " . $DB->sql_modulo('sortorder', MAX_COURSES_IN_CATEGORY) . " + ?\n                     WHERE category = ?";
            $DB->execute($sql, array($cat->sortorder, $cat->id));
        }
        $cacheevents['changesincoursecat'] = true;
    }
    unset($fixcategories);
    // categories having courses with sortorder duplicates or having gaps in sortorder
    $sql = "SELECT DISTINCT c1.category AS id , cc.sortorder\n              FROM {course} c1\n              JOIN {course} c2 ON c1.sortorder = c2.sortorder\n              JOIN {course_categories} cc ON (c1.category = cc.id)\n             WHERE c1.id <> c2.id";
    $fixcategories = $DB->get_records_sql($sql);
    $sql = "SELECT cc.id, cc.sortorder, cc.coursecount, MAX(c.sortorder) AS maxsort, MIN(c.sortorder) AS minsort\n              FROM {course_categories} cc\n              JOIN {course} c ON c.category = cc.id\n          GROUP BY cc.id, cc.sortorder, cc.coursecount\n            HAVING (MAX(c.sortorder) <>  cc.sortorder + cc.coursecount) OR (MIN(c.sortorder) <>  cc.sortorder + 1)";
    $gapcategories = $DB->get_records_sql($sql);
    foreach ($gapcategories as $cat) {
        if (isset($fixcategories[$cat->id])) {
            // duplicates detected already
        } else {
            if ($cat->minsort == $cat->sortorder and $cat->maxsort == $cat->sortorder + $cat->coursecount - 1) {
                // easy - new course inserted with sortorder 0, the rest is ok
                $sql = "UPDATE {course}\n                       SET sortorder = sortorder + 1\n                     WHERE category = ?";
                $DB->execute($sql, array($cat->id));
            } else {
                // it needs full resorting
                $fixcategories[$cat->id] = $cat;
            }
        }
        $cacheevents['changesincourse'] = true;
    }
    unset($gapcategories);
    // fix course sortorders in problematic categories only
    foreach ($fixcategories as $cat) {
        $i = 1;
        $courses = $DB->get_records('course', array('category' => $cat->id), 'sortorder ASC, id DESC', 'id, sortorder');
        foreach ($courses as $course) {
            if ($course->sortorder != $cat->sortorder + $i) {
                $course->sortorder = $cat->sortorder + $i;
                $DB->update_record_raw('course', $course, true);
                $cacheevents['changesincourse'] = true;
            }
            $i++;
        }
    }
    // advise all caches that need to be rebuilt
    foreach (array_keys($cacheevents) as $event) {
        cache_helper::purge_by_event($event);
    }
}
 /**
  * Returns a cache identification string.
  *
  * @return string A string to be used as part of keys.
  */
 protected function get_cache_identifier()
 {
     $identifiers = array();
     if ($this->selectedsharingoption & self::SHARING_ALL) {
         // Nothing to do here.
     } else {
         if ($this->selectedsharingoption & self::SHARING_SITEID) {
             $identifiers[] = cache_helper::get_site_identifier();
         }
         if ($this->selectedsharingoption & self::SHARING_VERSION) {
             $identifiers[] = cache_helper::get_site_version();
         }
         if ($this->selectedsharingoption & self::SHARING_INPUT && !empty($this->userinputsharingkey)) {
             $identifiers[] = $this->userinputsharingkey;
         }
     }
     return join('/', $identifiers);
 }
Example #30
0
/**
 * Changes the sort order of courses in a category so that the first course appears after the second.
 *
 * @param int|stdClass $courseorid The course to focus on.
 * @param int $moveaftercourseid The course to shifter after or 0 if you want it to be the first course in the category.
 * @return bool
 */
function course_change_sortorder_after_course($courseorid, $moveaftercourseid)
{
    global $DB;
    if (!is_object($courseorid)) {
        $course = get_course($courseorid);
    } else {
        $course = $courseorid;
    }
    if ((int) $moveaftercourseid === 0) {
        // We've moving the course to the start of the queue.
        $sql = 'SELECT sortorder
                      FROM {course}
                     WHERE category = :categoryid
                  ORDER BY sortorder';
        $params = array('categoryid' => $course->category);
        $sortorder = $DB->get_field_sql($sql, $params, IGNORE_MULTIPLE);
        $sql = 'UPDATE {course}
                   SET sortorder = sortorder + 1
                 WHERE category = :categoryid
                   AND id <> :id';
        $params = array('categoryid' => $course->category, 'id' => $course->id);
        $DB->execute($sql, $params);
        $DB->set_field('course', 'sortorder', $sortorder, array('id' => $course->id));
    } else {
        if ($course->id === $moveaftercourseid) {
            // They're the same - moronic.
            debugging("Invalid move after course given.", DEBUG_DEVELOPER);
            return false;
        } else {
            // Moving this course after the given course. It could be before it could be after.
            $moveaftercourse = get_course($moveaftercourseid);
            if ($course->category !== $moveaftercourse->category) {
                debugging("Cannot re-order courses. The given courses do not belong to the same category.", DEBUG_DEVELOPER);
                return false;
            }
            // Increment all courses in the same category that are ordered after the moveafter course.
            // This makes a space for the course we're moving.
            $sql = 'UPDATE {course}
                       SET sortorder = sortorder + 1
                     WHERE category = :categoryid
                       AND sortorder > :sortorder';
            $params = array('categoryid' => $moveaftercourse->category, 'sortorder' => $moveaftercourse->sortorder);
            $DB->execute($sql, $params);
            $DB->set_field('course', 'sortorder', $moveaftercourse->sortorder + 1, array('id' => $course->id));
        }
    }
    fix_course_sortorder();
    cache_helper::purge_by_event('changesincourse');
    return true;
}