/**
 * upgrade_b2evo_tables(-)
 *
 * @param string the action param value corresponding the current upgrade process ( evoupgrade, svn_upgrade, auto_upgrade )
 */
function upgrade_b2evo_tables($upgrade_action = 'evoupgrade')
{
    global $db_config, $tableprefix;
    global $baseurl, $old_db_version, $new_db_version;
    global $Group_Admins, $Group_Privileged, $Group_Bloggers, $Group_Users;
    global $locales, $locale;
    global $DB;
    global $admin_url;
    global $Settings, $Plugins;
    // used for defaults, when upgrading to 1.6
    global $use_fileupload, $fileupload_allowedtypes, $fileupload_maxk, $doubleCheckReferers;
    // new DB-delta functionality
    global $schema_queries, $inc_path;
    // used to check script time before starting to create db delta
    global $script_start_time;
    // Create an option which can be turned on if we need to regenerate the autogenerated excerpts in the end of the upgrade script
    global $recreate_autogenerated_excerpts;
    $recreate_autogenerated_excerpts = param('recreate_excerpts', 'boolean', 0);
    // Load DB schema from modules
    load_db_schema();
    // Update the progress bar status
    update_install_progress_bar();
    load_funcs('_core/model/db/_upgrade.funcs.php');
    // Force MySQL strict mode:
    $DB->query('SET sql_mode = ""', 'REMOVE MySQL "strict" mode in order not to worry about missing defaults until the end of the upgrade.');
    echo '<p>' . T_('Checking DB schema version...') . ' ';
    $old_db_version = get_db_version();
    if (empty($old_db_version)) {
        echo '<p><strong>OOPS! b2evolution doesn\'t seem to be installed yet.</strong></p>';
        return false;
    }
    echo $old_db_version, ' : ';
    if ($old_db_version < 8000) {
        debug_die(T_('This version is too old!'));
    }
    if ($old_db_version > $new_db_version) {
        debug_die(T_('This version is too recent! We cannot downgrade to the version you are trying to install...'));
    }
    echo "OK.<br />\n";
    if ($old_db_version < 8010) {
        echo 'Upgrading users table... ';
        $query = "ALTER TABLE T_users\n\t\t\t\t\t\t\tMODIFY COLUMN user_pass CHAR(32) NOT NULL";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading blogs table... ';
        $query = "ALTER TABLE T_blogs\n\t\t\t\t\t\t\tMODIFY COLUMN blog_lang VARCHAR(20) NOT NULL DEFAULT 'en_US',\n\t\t\t\t\t\t\tMODIFY COLUMN blog_longdesc TEXT NULL DEFAULT NULL";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading categories table... ';
        $query = "ALTER TABLE T_categories\n\t\t\t\t\t\t\tADD COLUMN cat_description VARCHAR(250) NULL DEFAULT NULL,\n\t\t\t\t\t\t\tADD COLUMN cat_longdesc TEXT NULL DEFAULT NULL,\n\t\t\t\t\t\t\tADD COLUMN cat_icon VARCHAR(30) NULL DEFAULT NULL";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading posts table... ';
        $query = "ALTER TABLE {$tableprefix}posts\n\t\t\t\t\t\t\tMODIFY COLUMN post_lang VARCHAR(20) NOT NULL DEFAULT 'en_US',\n\t\t\t\t\t\t\tADD COLUMN post_urltitle VARCHAR(50) NULL DEFAULT NULL AFTER post_title,\n\t\t\t\t\t\t\tADD COLUMN post_url VARCHAR(250) NULL DEFAULT NULL AFTER post_urltitle,\n\t\t\t\t\t\t\tADD COLUMN post_comments ENUM('disabled', 'open', 'closed') NOT NULL DEFAULT 'open' AFTER post_wordcount";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Generating wordcounts... ';
        load_funcs('items/model/_item.funcs.php');
        $query = "SELECT ID, post_content FROM {$tableprefix}posts WHERE post_wordcount IS NULL";
        $i = 0;
        foreach ($DB->get_results($query, ARRAY_A) as $row) {
            $query_update_wordcount = "UPDATE {$tableprefix}posts\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSET post_wordcount = " . bpost_count_words($row['post_content']) . "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE ID = " . $row['ID'];
            $DB->query($query_update_wordcount);
            $i++;
        }
        echo "OK. ({$i} rows updated)<br />\n";
        set_upgrade_checkpoint('8010');
    }
    if ($old_db_version < 8020) {
        echo 'Encoding passwords... ';
        $query = "UPDATE T_users\n\t\t\t\t\t\t\tSET user_pass = MD5(user_pass)";
        $DB->query($query);
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8020');
    }
    if ($old_db_version < 8030) {
        echo 'Deleting unecessary logs... ';
        $query = "DELETE FROM T_hitlog\n\t\t\t\t\t\t\tWHERE hit_ignore = 'badchar'";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Updating blog urls... ';
        $query = "SELECT blog_ID, blog_siteurl FROM T_blogs";
        $i = 0;
        foreach ($DB->get_results($query, ARRAY_A) as $row) {
            $blog_ID = $row['blog_ID'];
            $blog_siteurl = $row['blog_siteurl'];
            // echo $blog_ID.':'.$blog_siteurl;
            if (strpos($blog_siteurl . '/', $baseurl) !== 0) {
                // If not found at position 0
                echo ' <strong>WARNING: please check blog #', $blog_ID, ' manually.</strong><br /> ';
                continue;
            }
            // crop off the baseurl:
            $blog_siteurl = utf8_substr($blog_siteurl . '/', utf8_strlen($baseurl));
            // echo ' -> ', $blog_siteurl,'<br />';
            $query_update_blog = "UPDATE T_blogs SET blog_siteurl = '{$blog_siteurl}' WHERE blog_ID = {$blog_ID}";
            // echo $query_update_blog, '<br />';
            $DB->query($query_update_blog);
            $i++;
        }
        echo "OK. ({$i} rows updated)<br />\n";
        set_upgrade_checkpoint('8030');
    }
    if ($old_db_version < 8040) {
        // upgrade to 0.8.7
        echo 'Creating table for Antispam Blackist... ';
        $query = "CREATE TABLE {$tableprefix}antispam (\n\t\t\taspm_ID bigint(11) NOT NULL auto_increment,\n\t\t\taspm_string varchar(80) NOT NULL,\n\t\t\taspm_source enum( 'local','reported','central' ) NOT NULL default 'reported',\n\t\t\tPRIMARY KEY aspm_ID (aspm_ID),\n\t\t\tUNIQUE aspm_string (aspm_string)\n\t\t)";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Creating default blacklist entries... ';
        // This string contains antispam information that is obfuscated because some hosting
        // companies prevent uploading PHP files containing "spam" strings.
        // pre_dump(get_antispam_query());
        $query = get_antispam_query();
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading Settings table... ';
        $query = "ALTER TABLE T_settings\n\t\t\t\t\t\t\tADD COLUMN last_antispam_update datetime NOT NULL default '2000-01-01 00:00:00'";
        $DB->query($query);
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8040');
    }
    if ($old_db_version < 8050) {
        // upgrade to 0.8.9
        echo 'Upgrading blogs table... ';
        $query = "ALTER TABLE T_blogs\n\t\t\t\t\t\t\tADD COLUMN blog_allowtrackbacks tinyint(1) NOT NULL default 1,\n\t\t\t\t\t\t\tADD COLUMN blog_allowpingbacks tinyint(1) NOT NULL default 0,\n\t\t\t\t\t\t\tADD COLUMN blog_pingb2evonet tinyint(1) NOT NULL default 0,\n\t\t\t\t\t\t\tADD COLUMN blog_pingtechnorati tinyint(1) NOT NULL default 0,\n\t\t\t\t\t\t\tADD COLUMN blog_pingweblogs tinyint(1) NOT NULL default 0,\n\t\t\t\t\t\t\tADD COLUMN blog_pingblodotgs tinyint(1) NOT NULL default 0,\n\t\t\t\t\t\t\tADD COLUMN blog_disp_bloglist tinyint NOT NULL DEFAULT 1";
        $DB->query($query);
        echo "OK.<br />\n";
        // Create User Groups
        global $Group_Admins, $Group_Privileged, $Group_Bloggers, $Group_Users;
        echo 'Creating table for Groups... ';
        $query = "CREATE TABLE T_groups (\n\t\t\tgrp_ID int(11) NOT NULL auto_increment,\n\t\t\tgrp_name varchar(50) NOT NULL default '',\n\t\t\tgrp_perm_admin enum('none','hidden','visible') NOT NULL default 'visible',\n\t\t\tgrp_perm_blogs enum('user','viewall','editall') NOT NULL default 'user',\n\t\t\tgrp_perm_stats enum('none','view','edit') NOT NULL default 'none',\n\t\t\tgrp_perm_spamblacklist enum('none','view','edit') NOT NULL default 'none',\n\t\t\tgrp_perm_options enum('none','view','edit') NOT NULL default 'none',\n\t\t\tgrp_perm_users enum('none','view','edit') NOT NULL default 'none',\n\t\t\tgrp_perm_templates TINYINT NOT NULL DEFAULT 0,\n\t\t\tgrp_perm_files enum('none','view','add','edit','all') NOT NULL default 'none',\n\t\t\tPRIMARY KEY grp_ID (grp_ID)\n\t\t)";
        $DB->query($query);
        echo "OK.<br />\n";
        // This table needs to be created here for proper group insertion
        task_begin('Creating table for Group Settings... ');
        $DB->query("CREATE TABLE T_groups__groupsettings (\n\t\t\tgset_grp_ID INT(11) UNSIGNED NOT NULL,\n\t\t\tgset_name VARCHAR(30) NOT NULL,\n\t\t\tgset_value VARCHAR(255) NULL,\n\t\t\tPRIMARY KEY (gset_grp_ID, gset_name)\n\t\t) ENGINE = innodb");
        task_end();
        echo 'Creating default groups... ';
        $Group_Admins = new Group();
        // COPY !
        $Group_Admins->set('name', 'Administrators');
        $Group_Admins->set('perm_admin', 'visible');
        $Group_Admins->set('perm_blogs', 'editall');
        $Group_Admins->set('perm_stats', 'edit');
        $Group_Admins->set('perm_spamblacklist', 'edit');
        $Group_Admins->set('perm_files', 'all');
        $Group_Admins->set('perm_options', 'edit');
        $Group_Admins->set('perm_templates', 1);
        $Group_Admins->set('perm_users', 'edit');
        $Group_Admins->dbinsert();
        $Group_Privileged = new Group();
        // COPY !
        $Group_Privileged->set('name', 'Privileged Bloggers');
        $Group_Privileged->set('perm_admin', 'visible');
        $Group_Privileged->set('perm_blogs', 'viewall');
        $Group_Privileged->set('perm_stats', 'view');
        $Group_Privileged->set('perm_spamblacklist', 'edit');
        $Group_Privileged->set('perm_files', 'add');
        $Group_Privileged->set('perm_options', 'view');
        $Group_Privileged->set('perm_templates', 0);
        $Group_Privileged->set('perm_users', 'view');
        $Group_Privileged->dbinsert();
        $Group_Bloggers = new Group();
        // COPY !
        $Group_Bloggers->set('name', 'Bloggers');
        $Group_Bloggers->set('perm_admin', 'visible');
        $Group_Bloggers->set('perm_blogs', 'user');
        $Group_Bloggers->set('perm_stats', 'none');
        $Group_Bloggers->set('perm_spamblacklist', 'view');
        $Group_Bloggers->set('perm_files', 'view');
        $Group_Bloggers->set('perm_options', 'none');
        $Group_Bloggers->set('perm_templates', 0);
        $Group_Bloggers->set('perm_users', 'none');
        $Group_Bloggers->dbinsert();
        $Group_Users = new Group();
        // COPY !
        $Group_Users->set('name', 'Basic Users');
        $Group_Users->set('perm_admin', 'none');
        $Group_Users->set('perm_blogs', 'user');
        $Group_Users->set('perm_stats', 'none');
        $Group_Users->set('perm_spamblacklist', 'none');
        $Group_Users->set('perm_files', 'none');
        $Group_Users->set('perm_options', 'none');
        $Group_Users->set('perm_templates', 0);
        $Group_Users->set('perm_users', 'none');
        $Group_Users->dbinsert();
        echo "OK.<br />\n";
        echo 'Creating table for Blog-User permissions... ';
        $query = "CREATE TABLE T_coll_user_perms (\n\t\t\tbloguser_blog_ID int(11) unsigned NOT NULL default 0,\n\t\t\tbloguser_user_ID int(11) unsigned NOT NULL default 0,\n\t\t\tbloguser_ismember tinyint NOT NULL default 0,\n\t\t\tbloguser_perm_poststatuses set('published','deprecated','protected','private','draft') NOT NULL default '',\n\t\t\tbloguser_perm_delpost tinyint NOT NULL default 0,\n\t\t\tbloguser_perm_comments tinyint NOT NULL default 0,\n\t\t\tbloguser_perm_cats tinyint NOT NULL default 0,\n\t\t\tbloguser_perm_properties tinyint NOT NULL default 0,\n\t\t\tbloguser_perm_media_upload tinyint NOT NULL default 0,\n\t\t\tbloguser_perm_media_browse tinyint NOT NULL default 0,\n\t\t\tbloguser_perm_media_change tinyint NOT NULL default 0,\n\t\t\tPRIMARY KEY bloguser_pk (bloguser_blog_ID,bloguser_user_ID)\n\t\t)";
        $DB->query($query);
        echo "OK.<br />\n";
        $tablegroups_isuptodate = true;
        $tableblogusers_isuptodate = true;
        echo 'Creating user blog permissions... ';
        // Admin: full rights for all blogs (look 'ma, doing a natural join! :>)
        $query = "INSERT INTO T_coll_user_perms( bloguser_blog_ID, bloguser_user_ID, bloguser_ismember,\n\t\t\t\t\t\t\t\tbloguser_perm_poststatuses, bloguser_perm_delpost, bloguser_perm_comments,\n\t\t\t\t\t\t\t\tbloguser_perm_cats, bloguser_perm_properties)\n\t\t\t\t\t\t\tSELECT blog_ID, ID, 1, 'published,deprecated,protected,private,draft', 1, 1, 1, 1\n\t\t\t\t\t\t\tFROM T_users, T_blogs\n\t\t\t\t\t\t\tWHERE user_level = 10";
        $DB->query($query);
        // Normal users: basic rights for all blogs (can't stop doing joins :P)
        $query = "INSERT INTO T_coll_user_perms( bloguser_blog_ID, bloguser_user_ID, bloguser_ismember,\n\t\t\t\t\t\t\t\tbloguser_perm_poststatuses, bloguser_perm_delpost, bloguser_perm_comments,\n\t\t\t\t\t\t\t\tbloguser_perm_cats, bloguser_perm_properties)\n\t\t\t\t\t\t\tSELECT blog_ID, ID, 1, 'published,protected,private,draft', 0, 1, 0, 0\n\t\t\t\t\t\t\tFROM T_users, T_blogs\n\t\t\t\t\t\t\tWHERE user_level > 0 AND user_level < 10";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading users table... ';
        $DB->query('UPDATE T_users
									  SET dateYMDhour = \'2000-01-01 00:00:00\'
									WHERE ( dateYMDhour = \'0000-00-00 00:00:00\' OR dateYMDhour = \'2000-00-00 00:00:01\' )');
        $DB->query('ALTER TABLE T_users
							MODIFY COLUMN dateYMDhour DATETIME NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $query = "ALTER TABLE T_users\n\t\t\t\t\t\t\tADD COLUMN user_notify tinyint(1) NOT NULL default 1,\n\t\t\t\t\t\t\tADD COLUMN user_grp_ID int(4) NOT NULL default 1,\n\t\t\t\t\t\t\tMODIFY COLUMN user_idmode varchar(20) NOT NULL DEFAULT 'login'";
        $DB->query($query);
        $query = "ALTER TABLE T_users\n\t\t\t\t\t\t\tADD KEY user_grp_ID (user_grp_ID)";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Assigning user groups... ';
        // Default is 1, so admins are already set.
        // Basic Users:
        $query = "UPDATE T_users\n\t\t\t\t\t\t\tSET user_grp_ID = {$Group_Users->ID}\n\t\t\t\t\t\t\tWHERE user_level = 0";
        $DB->query($query);
        // Bloggers:
        $query = "UPDATE T_users\n\t\t\t\t\t\t\tSET user_grp_ID = {$Group_Bloggers->ID}\n\t\t\t\t\t\t\tWHERE user_level > 0 AND user_level < 10";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading settings table... ';
        $query = "ALTER TABLE T_settings\n\t\t\t\t\t\t\tDROP COLUMN time_format,\n\t\t\t\t\t\t\tDROP COLUMN date_format,\n\t\t\t\t\t\t\tADD COLUMN pref_newusers_grp_ID int unsigned DEFAULT 4 NOT NULL,\n\t\t\t\t\t\t\tADD COLUMN pref_newusers_level tinyint unsigned DEFAULT 1 NOT NULL,\n\t\t\t\t\t\t\tADD COLUMN pref_newusers_canregister tinyint unsigned DEFAULT 0 NOT NULL";
        $DB->query($query);
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8050');
    }
    if ($old_db_version < 8060) {
        // upgrade to 0.9
        // Important check:
        $stub_list = $DB->get_col("\n\t\t\tSELECT blog_stub\n\t\t\t  FROM T_blogs\n\t\t\t GROUP BY blog_stub\n\t\t\tHAVING COUNT(*) > 1");
        if (!empty($stub_list)) {
            echo '<div class="error"><p class="error">';
            printf(T_("It appears that the following blog stub names are used more than once: ['%s']"), implode("','", $stub_list));
            echo '</p><p>';
            printf(T_("I can't upgrade until you make them unique. DB field: [%s]"), $db_config['aliases']['T_blogs'] . '.blog_stub');
            echo '</p></div>';
            return false;
        }
        // Create locales
        echo 'Creating table for Locales... ';
        $query = "CREATE TABLE T_locales (\n\t\t\t\tloc_locale varchar(20) NOT NULL default '',\n\t\t\t\tloc_charset varchar(15) NOT NULL default 'iso-8859-1',\n\t\t\t\tloc_datefmt varchar(10) NOT NULL default 'y-m-d',\n\t\t\t\tloc_timefmt varchar(10) NOT NULL default 'H:i:s',\n\t\t\t\tloc_name varchar(40) NOT NULL default '',\n\t\t\t\tloc_messages varchar(20) NOT NULL default '',\n\t\t\t\tloc_priority tinyint(4) UNSIGNED NOT NULL default '0',\n\t\t\t\tloc_enabled tinyint(4) NOT NULL default '1',\n\t\t\t\tPRIMARY KEY loc_locale( loc_locale )\n\t\t\t) COMMENT='saves available locales'";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading posts table... ';
        $query = "UPDATE {$tableprefix}posts\n\t\t\t\t\t\t\tSET post_urltitle = NULL";
        $DB->query($query);
        $query = "ALTER TABLE {$tableprefix}posts\n\t\t\t\t\t\t\tCHANGE COLUMN post_date post_issue_date datetime NOT NULL default '1000-01-01 00:00:00',\n\t\t\t\t\t\t\tADD COLUMN post_mod_date datetime NOT NULL default '1000-01-01 00:00:00'\n\t\t\t\t\t\t\t\t\t\tAFTER post_issue_date,\n\t\t\t\t\t\t\tCHANGE COLUMN post_lang post_locale varchar(20) NOT NULL default 'en-EU',\n\t\t\t\t\t\t\tDROP COLUMN post_url,\n\t\t\t\t\t\t\tCHANGE COLUMN post_trackbacks post_url varchar(250) NULL default NULL,\n\t\t\t\t\t\t\tADD COLUMN post_renderers VARCHAR(179) NOT NULL default 'default'";
        $DB->query($query);
        $query = "ALTER TABLE {$tableprefix}posts\n\t\t\t\t\t\t\tADD INDEX post_issue_date( post_issue_date ),\n\t\t\t\t\t\t\tADD UNIQUE post_urltitle( post_urltitle )";
        $DB->query($query);
        $query = "ALTER TABLE {$tableprefix}posts\n\t\t\t\t\tDROP INDEX post_date";
        $DB->query($query);
        $query = "UPDATE {$tableprefix}posts\n\t\t\t\t\t\t\tSET post_mod_date = post_issue_date";
        $DB->query($query);
        echo "OK.<br />\n";
        // convert given languages to locales
        convert_lang_to_locale("{$tableprefix}posts", 'post_locale', 'ID');
        echo 'Upgrading blogs table... ';
        $query = "ALTER TABLE T_blogs\n\t\t\t\t\t\t\tCHANGE blog_lang blog_locale varchar(20) NOT NULL default 'en-EU',\n\t\t\t\t\t\t\tCHANGE blog_roll blog_notes TEXT NULL,\n\t\t\t\t\t\t\tMODIFY COLUMN blog_default_skin VARCHAR(30) NOT NULL DEFAULT 'custom',\n\t\t\t\t\t\t\tDROP COLUMN blog_filename,\n\t\t\t\t\t\t\tADD COLUMN blog_access_type VARCHAR(10) NOT NULL DEFAULT 'index.php' AFTER blog_locale,\n\t\t\t\t\t\t\tADD COLUMN blog_force_skin tinyint(1) NOT NULL default 0 AFTER blog_default_skin,\n\t\t\t\t\t\t\tADD COLUMN blog_in_bloglist tinyint(1) NOT NULL DEFAULT 1 AFTER blog_disp_bloglist,\n\t\t\t\t\t\t\tADD COLUMN blog_links_blog_ID INT(4) NOT NULL DEFAULT 0,\n\t\t\t\t\t\t\tADD UNIQUE KEY blog_stub (blog_stub)";
        $DB->query($query);
        $query = "UPDATE T_blogs\n\t\t\t\t\t\t\tSET blog_access_type = 'stub',\n\t\t\t\t\t\t\t\t\tblog_default_skin = 'custom'";
        $DB->query($query);
        echo "OK.<br />\n";
        // convert given languages to locales
        convert_lang_to_locale('T_blogs', 'blog_locale', 'blog_ID');
        echo 'Converting settings table... ';
        // get old settings
        $query = 'SELECT * FROM T_settings';
        $row = $DB->get_row($query, ARRAY_A);
        #echo 'oldrow:<br />'; pre_dump($row);
        $transform = array('posts_per_page' => array(5), 'what_to_show' => array('posts'), 'archive_mode' => array('monthly'), 'time_difference' => array(0), 'AutoBR' => array(0), 'last_antispam_update' => array('2000-01-01 00:00:00', 'antispam_last_update'), 'pref_newusers_grp_ID' => array($Group_Users->ID, 'newusers_grp_ID'), 'pref_newusers_level' => array(1, 'newusers_level'), 'pref_newusers_canregister' => array(0, 'newusers_canregister'));
        $_trans = array();
        foreach ($transform as $oldkey => $newarr) {
            $newname = isset($newarr[1]) ? $newarr[1] : $oldkey;
            if (!isset($row[$oldkey])) {
                echo '&nbsp;&middot;Setting ' . $oldkey . ' not found, using defaults.<br />';
                $_trans[$newname] = $newarr[0];
            } else {
                $_trans[$newname] = $row[$oldkey];
            }
        }
        // drop old table
        $DB->query('DROP TABLE IF EXISTS T_settings');
        // create new table
        $DB->query('CREATE TABLE T_settings (
				set_name VARCHAR( 30 ) NOT NULL ,
				set_value VARCHAR( 255 ) NULL ,
				PRIMARY KEY ( set_name )
			)');
        // insert defaults and use transformed settings
        create_default_settings($_trans);
        if (!isset($tableblogusers_isuptodate)) {
            echo 'Upgrading Blog-User permissions table... ';
            $query = "ALTER TABLE T_coll_user_perms\n\t\t\t\t\t\t\t\tADD COLUMN bloguser_ismember tinyint NOT NULL default 0 AFTER bloguser_user_ID";
            $DB->query($query);
            // Any row that is created holds at least one permission,
            // minimum permsission is to be a member, so we add that one too, to all existing rows.
            $DB->query("UPDATE T_coll_user_perms\n\t\t\t\t\t\t\t\t\t\t\tSET bloguser_ismember = 1");
            echo "OK.<br />\n";
        }
        echo 'Upgrading Comments table... ';
        $DB->query('UPDATE T_comments
									  SET comment_date = \'2000-01-01 00:00:00\'
									WHERE comment_date = \'0000-00-00 00:00:00\'');
        $DB->query('ALTER TABLE T_comments
							MODIFY COLUMN comment_date DATETIME NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $query = "ALTER TABLE T_comments\n\t\t\t\t\t\t\tADD COLUMN comment_author_ID int unsigned NULL default NULL AFTER comment_status,\n\t\t\t\t\t\t\tMODIFY COLUMN comment_author varchar(100) NULL,\n\t\t\t\t\t\t\tMODIFY COLUMN comment_author_email varchar(100) NULL,\n\t\t\t\t\t\t\tMODIFY COLUMN comment_author_url varchar(100) NULL,\n\t\t\t\t\t\t\tMODIFY COLUMN comment_author_IP varchar(23) NOT NULL default ''";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading Users table... ';
        $query = "ALTER TABLE T_users ADD user_locale VARCHAR( 20 ) DEFAULT 'en-EU' NOT NULL AFTER user_yim";
        $DB->query($query);
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8060');
    }
    if ($old_db_version < 8062) {
        // upgrade to 0.9.0.4
        echo "Checking for extra quote escaping in posts... ";
        $query = "SELECT ID, post_title, post_content\n\t\t\t\t\t\t\t\tFROM {$tableprefix}posts\n\t\t\t\t\t\t\t WHERE post_title LIKE '%\\\\\\\\\\'%'\n\t\t\t\t\t\t\t\t\tOR post_title LIKE '%\\\\\\\\\"%'\n\t\t\t\t\t\t\t\t\tOR post_content LIKE '%\\\\\\\\\\'%'\n\t\t\t\t\t\t\t\t\tOR post_content LIKE '%\\\\\\\\\"%' ";
        /* FP: the above looks overkill, but MySQL is really full of surprises...
        			tested on 4.0.14-nt */
        // echo $query;
        $rows = $DB->get_results($query, ARRAY_A);
        if ($DB->num_rows) {
            echo 'Updating ' . $DB->num_rows . ' posts... ';
            foreach ($rows as $row) {
                // echo '<br />'.$row['post_title'];
                $query = "UPDATE {$tableprefix}posts\n\t\t\t\t\t\t\t\t\tSET post_title = " . $DB->quote(stripslashes($row['post_title'])) . ",\n\t\t\t\t\t\t\t\t\t\t\tpost_content = " . $DB->quote(stripslashes($row['post_content'])) . "\n\t\t\t\t\t\t\t\t\tWHERE ID = " . $row['ID'];
                // echo '<br />'.$query;
                $DB->query($query);
            }
        }
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8062');
    }
    if ($old_db_version < 8064) {
        // upgrade to 0.9.0.6
        cleanup_comment_quotes();
        set_upgrade_checkpoint('8064');
    }
    if ($old_db_version < 8066) {
        // upgrade to 0.9.1
        echo 'Adding catpost index... ';
        $DB->query('ALTER TABLE T_postcats ADD UNIQUE catpost ( postcat_cat_ID, postcat_post_ID )');
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8066');
    }
    if ($old_db_version < 8800) {
        // ---------------------------------- upgrade to 1.6 "phoenix ALPHA"
        echo 'Dropping old Hitlog table... ';
        $DB->query('DROP TABLE IF EXISTS T_hitlog');
        echo "OK.<br />\n";
        // New tables:
        echo 'Creating table for active sessions... ';
        $DB->query("CREATE TABLE T_sessions (\n\t\t\t\t\t\t\t\t\t\t\tsess_ID        INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,\n\t\t\t\t\t\t\t\t\t\t\tsess_key       CHAR(32) NULL,\n\t\t\t\t\t\t\t\t\t\t\tsess_lastseen  DATETIME NOT NULL,\n\t\t\t\t\t\t\t\t\t\t\tsess_ipaddress VARCHAR(15) NOT NULL DEFAULT '',\n\t\t\t\t\t\t\t\t\t\t\tsess_user_ID   INT(10) DEFAULT NULL,\n\t\t\t\t\t\t\t\t\t\t\tsess_agnt_ID   INT UNSIGNED NULL,\n\t\t\t\t\t\t\t\t\t\t\tsess_data      TEXT DEFAULT NULL,\n\t\t\t\t\t\t\t\t\t\t\tPRIMARY KEY( sess_ID )\n\t\t\t\t\t\t\t\t\t\t)");
        echo "OK.<br />\n";
        echo 'Creating user settings table... ';
        $DB->query("CREATE TABLE {$tableprefix}usersettings (\n\t\t\t\t\t\t\t\t\t\t\tuset_user_ID INT(11) UNSIGNED NOT NULL,\n\t\t\t\t\t\t\t\t\t\t\tuset_name    VARCHAR( 30 ) NOT NULL,\n\t\t\t\t\t\t\t\t\t\t\tuset_value   VARCHAR( 255 ) NULL,\n\t\t\t\t\t\t\t\t\t\t\tPRIMARY KEY ( uset_user_ID, uset_name )\n\t\t\t\t\t\t\t\t\t\t)");
        echo "OK.<br />\n";
        echo 'Creating plugins table... ';
        $DB->query("CREATE TABLE T_plugins (\n\t\t\t\t\t\t\t\t\t\t\tplug_ID        INT(11) UNSIGNED NOT NULL auto_increment,\n\t\t\t\t\t\t\t\t\t\t\tplug_priority  INT(11) NOT NULL default 50,\n\t\t\t\t\t\t\t\t\t\t\tplug_classname VARCHAR(40) NOT NULL default '',\n\t\t\t\t\t\t\t\t\t\t\tPRIMARY KEY ( plug_ID )\n\t\t\t\t\t\t\t\t\t\t)");
        echo "OK.<br />\n";
        echo 'Creating table for Post Statuses... ';
        $query = "CREATE TABLE {$tableprefix}poststatuses (\n\t\t\t\t\t\t\t\t\t\t\tpst_ID   int(11) unsigned not null AUTO_INCREMENT,\n\t\t\t\t\t\t\t\t\t\t\tpst_name varchar(30)      not null,\n\t\t\t\t\t\t\t\t\t\t\tprimary key ( pst_ID )\n\t\t\t\t\t\t\t\t\t\t)";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Creating table for Post Types... ';
        $query = "CREATE TABLE {$tableprefix}posttypes (\n\t\t\t\t\t\t\t\t\t\t\tptyp_ID   int(11) unsigned not null AUTO_INCREMENT,\n\t\t\t\t\t\t\t\t\t\t\tptyp_name varchar(30)      not null,\n\t\t\t\t\t\t\t\t\t\t\tprimary key (ptyp_ID)\n\t\t\t\t\t\t\t\t\t\t)";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Creating table for File Meta Data... ';
        $DB->query("CREATE TABLE T_files (\n\t\t\t\t\t\t\t\t\t\t file_ID        int(11) unsigned  not null AUTO_INCREMENT,\n\t\t\t\t\t\t\t\t\t\t file_root_type enum('absolute','user','group','collection') not null default 'absolute',\n\t\t\t\t\t\t\t\t\t\t file_root_ID   int(11) unsigned  not null default 0,\n\t\t\t\t\t\t\t\t\t\t file_path      varchar(255)      not null default '',\n\t\t\t\t\t\t\t\t\t\t file_title     varchar(255),\n\t\t\t\t\t\t\t\t\t\t file_alt       varchar(255),\n\t\t\t\t\t\t\t\t\t\t file_desc      text,\n\t\t\t\t\t\t\t\t\t\t primary key (file_ID),\n\t\t\t\t\t\t\t\t\t\t unique file (file_root_type, file_root_ID, file_path)\n\t\t\t\t\t\t\t\t\t)");
        echo "OK.<br />\n";
        echo 'Creating table for base domains... ';
        $DB->query("CREATE TABLE T_basedomains (\n\t\t\t\t\t\t\t\t\t\tdom_ID     INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,\n\t\t\t\t\t\t\t\t\t\tdom_name   VARCHAR(250) NOT NULL DEFAULT '',\n\t\t\t\t\t\t\t\t\t\tdom_status ENUM('unknown','whitelist','blacklist') NOT NULL DEFAULT 'unknown',\n\t\t\t\t\t\t\t\t\t\tdom_type   ENUM('unknown','normal','searcheng','aggregator') NOT NULL DEFAULT 'unknown',\n\t\t\t\t\t\t\t\t\t\tPRIMARY KEY (dom_ID),\n\t\t\t\t\t\t\t\t\t\tUNIQUE dom_name (dom_name)\n\t\t\t\t\t\t\t\t\t)");
        // fp> the unique key was only named in version 1.9. Crap. Put the name back here to save as many souls as possible. bulk has not upgraded from 0.9 yet :/
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8820');
    }
    if ($old_db_version < 8840) {
        echo 'Creating table for user agents... ';
        $DB->query("CREATE TABLE {$tableprefix}useragents (\n\t\t\t\t\t\t\t\t\t\tagnt_ID        INT UNSIGNED NOT NULL AUTO_INCREMENT,\n\t\t\t\t\t\t\t\t\t\tagnt_signature VARCHAR(250) NOT NULL,\n\t\t\t\t\t\t\t\t\t\tagnt_type      ENUM('rss','robot','browser','unknown') DEFAULT 'unknown' NOT NULL,\n\t\t\t\t\t\t\t\t\t\tPRIMARY KEY (agnt_ID) )");
        echo "OK.<br />\n";
        echo 'Creating table for Hit-Logs... ';
        $query = "CREATE TABLE T_hitlog (\n\t\t\t\t\t\t\t\t\thit_ID             INT(11) NOT NULL AUTO_INCREMENT,\n\t\t\t\t\t\t\t\t\thit_sess_ID        INT UNSIGNED,\n\t\t\t\t\t\t\t\t\thit_datetime       DATETIME NOT NULL,\n\t\t\t\t\t\t\t\t\thit_uri            VARCHAR(250) DEFAULT NULL,\n\t\t\t\t\t\t\t\t\thit_referer_type   ENUM('search','blacklist','referer','direct','spam') NOT NULL,\n\t\t\t\t\t\t\t\t\thit_referer        VARCHAR(250) DEFAULT NULL,\n\t\t\t\t\t\t\t\t\thit_referer_dom_ID INT UNSIGNED DEFAULT NULL,\n\t\t\t\t\t\t\t\t\thit_blog_ID        int(11) UNSIGNED NULL DEFAULT NULL,\n\t\t\t\t\t\t\t\t\thit_remote_addr    VARCHAR(40) DEFAULT NULL,\n\t\t\t\t\t\t\t\t\tPRIMARY KEY (hit_ID),\n\t\t\t\t\t\t\t\t\tINDEX hit_datetime ( hit_datetime ),\n\t\t\t\t\t\t\t\t\tINDEX hit_blog_ID (hit_blog_ID)\n\t\t\t\t\t\t\t\t)";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Creating table for subscriptions... ';
        $DB->query("CREATE TABLE T_subscriptions (\n\t\t\t\t\t\t\t\t\t\t sub_coll_ID     int(11) unsigned    not null,\n\t\t\t\t\t\t\t\t\t\t sub_user_ID     int(11) unsigned    not null,\n\t\t\t\t\t\t\t\t\t\t sub_items       tinyint(1)          not null,\n\t\t\t\t\t\t\t\t\t\t sub_comments    tinyint(1)          not null,\n\t\t\t\t\t\t\t\t\t\t primary key (sub_coll_ID, sub_user_ID)\n\t\t\t\t\t\t\t\t\t\t)");
        echo "OK.<br />\n";
        echo 'Creating table for blog-group permissions... ';
        $DB->query("CREATE TABLE T_coll_group_perms (\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_blog_ID int(11) unsigned NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_group_ID int(11) unsigned NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_ismember tinyint NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_perm_poststatuses set('published','deprecated','protected','private','draft') NOT NULL default '',\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_perm_delpost tinyint NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_perm_comments tinyint NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_perm_cats tinyint NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_perm_properties tinyint NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_perm_media_upload tinyint NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_perm_media_browse tinyint NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tbloggroup_perm_media_change tinyint NOT NULL default 0,\n\t\t\t\t\t\t\t\t\t\t\tPRIMARY KEY bloggroup_pk (bloggroup_blog_ID,bloggroup_group_ID) )");
        echo "OK.<br />\n";
        echo 'Upgrading blogs table... ';
        $query = "ALTER TABLE T_blogs\n\t\t\t\t\t\t\tMODIFY COLUMN blog_ID int(11) unsigned NOT NULL auto_increment,\n\t\t\t\t\t\t\tMODIFY COLUMN blog_links_blog_ID INT(11) NULL DEFAULT NULL,\n\t\t\t\t\t\t\tCHANGE COLUMN blog_stub blog_urlname VARCHAR(255) NOT NULL DEFAULT 'urlname',\n\t\t\t\t\t\t\tADD COLUMN blog_allowcomments VARCHAR(20) NOT NULL default 'post_by_post' AFTER blog_keywords,\n\t\t\t\t\t\t\tADD COLUMN blog_allowblogcss TINYINT(1) NOT NULL default 1 AFTER blog_allowpingbacks,\n\t\t\t\t\t\t\tADD COLUMN blog_allowusercss TINYINT(1) NOT NULL default 1 AFTER blog_allowblogcss,\n\t\t\t\t\t\t\tADD COLUMN blog_stub VARCHAR(255) NOT NULL DEFAULT 'stub' AFTER blog_staticfilename,\n\t\t\t\t\t\t\tADD COLUMN blog_commentsexpire INT(4) NOT NULL DEFAULT 0 AFTER blog_links_blog_ID,\n\t\t\t\t\t\t\tADD COLUMN blog_media_location ENUM( 'default', 'subdir', 'custom', 'none' ) DEFAULT 'default' NOT NULL AFTER blog_commentsexpire,\n\t\t\t\t\t\t\tADD COLUMN blog_media_subdir VARCHAR( 255 ) NOT NULL AFTER blog_media_location,\n\t\t\t\t\t\t\tADD COLUMN blog_media_fullpath VARCHAR( 255 ) NOT NULL AFTER blog_media_subdir,\n\t\t\t\t\t\t\tADD COLUMN blog_media_url VARCHAR(255) NOT NULL AFTER blog_media_fullpath";
        $DB->query($query);
        $query = "ALTER TABLE T_blogs\n\t\t\t\t\t\t\tADD UNIQUE blog_urlname ( blog_urlname )";
        $DB->query($query);
        $query = "ALTER TABLE T_blogs\n\t\t\t\t\t\t\tDROP INDEX blog_stub";
        $DB->query($query);
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8840');
    }
    // sam2kb>fp: We need to make sure there are no values like "blog_a.php" in blog_urlname,
    //			after this upgrade blog URLs look like $baseurl.'blog_a.php' which might be OK in 0.x version,
    //			but this config will not work in b2evo 4. Blog URLs will be broken!
    if ($old_db_version < 8850) {
        echo 'Updating relative URLs... ';
        // We need to move the slashes to the end:
        $query = "UPDATE T_blogs\n\t\t\t\t\t\t\t\t SET blog_siteurl = CONCAT( SUBSTRING(blog_siteurl,2) , '/' )\n\t\t\t\t\t\t\t WHERE blog_siteurl LIKE '/%'";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Copying urlnames to stub names... ';
        $query = 'UPDATE T_blogs
							SET blog_stub = blog_urlname';
        $DB->query($query);
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8850');
    }
    if ($old_db_version < 8855) {
        echo 'Upgrading posts table... ';
        $query = "ALTER TABLE {$tableprefix}posts\n\t\t\t\t\t\t\tDROP INDEX post_author,\n\t\t\t\t\t\t\tDROP INDEX post_issue_date,\n\t\t\t\t\t\t\tDROP INDEX post_category";
        $DB->query($query);
        $query = "ALTER TABLE {$tableprefix}posts\n\t\t\t\t\t\t\tDROP COLUMN post_karma,\n\t\t\t\t\t\t\tDROP COLUMN post_autobr,\n\t\t\t\t\t\t\tCHANGE COLUMN ID post_ID int(11) unsigned NOT NULL auto_increment,\n\t\t\t\t\t\t\tCHANGE COLUMN post_author\tpost_creator_user_ID int(11) unsigned NOT NULL,\n\t\t\t\t\t\t\tCHANGE COLUMN post_issue_date\tpost_datestart datetime NOT NULL,\n\t\t\t\t\t\t\tCHANGE COLUMN post_mod_date\tpost_datemodified datetime NOT NULL,\n\t\t\t\t\t\t\tCHANGE COLUMN post_category post_main_cat_ID int(11) unsigned NOT NULL,\n\t\t\t\t\t\t\tADD post_parent_ID\t\t\t\tint(11) unsigned NULL AFTER post_ID,\n\t\t\t\t\t\t\tADD post_lastedit_user_ID\tint(11) unsigned NULL AFTER post_creator_user_ID,\n\t\t\t\t\t\t\tADD post_assigned_user_ID\tint(11) unsigned NULL AFTER post_lastedit_user_ID,\n\t\t\t\t\t\t\tADD post_datedeadline \t\tdatetime NULL AFTER post_datestart,\n\t\t\t\t\t\t\tADD post_datecreated\t\t\tdatetime NULL AFTER post_datedeadline,\n\t\t\t\t\t\t\tADD post_pst_ID\t\t\t\t\t\tint(11) unsigned NULL AFTER post_status,\n\t\t\t\t\t\t\tADD post_ptyp_ID\t\t\t\t\tint(11) unsigned NULL AFTER post_pst_ID,\n\t\t\t\t\t\t\tADD post_views\t\t\t\t\t\tint(11) unsigned NOT NULL DEFAULT 0 AFTER post_flags,\n\t\t\t\t\t\t\tADD post_commentsexpire\t\tdatetime DEFAULT NULL AFTER post_comments,\n\t\t\t\t\t\t\tADD post_priority\t\t\t\t\tint(11) unsigned null";
        $DB->query($query);
        $query = "ALTER TABLE {$tableprefix}posts\n\t\t\t\t\t\t\tADD INDEX post_creator_user_ID( post_creator_user_ID ),\n\t\t\t\t\t\t\tADD INDEX post_parent_ID( post_parent_ID ),\n\t\t\t\t\t\t\tADD INDEX post_assigned_user_ID( post_assigned_user_ID ),\n\t\t\t\t\t\t\tADD INDEX post_datestart( post_datestart ),\n\t\t\t\t\t\t\tADD INDEX post_main_cat_ID( post_main_cat_ID ),\n\t\t\t\t\t\t\tADD INDEX post_ptyp_ID( post_ptyp_ID ),\n\t\t\t\t\t\t\tADD INDEX post_pst_ID( post_pst_ID ) ";
        $DB->query($query);
        echo "OK.<br />\n";
        set_upgrade_checkpoint('8855');
    }
    if ($old_db_version < 8860) {
        echo 'Updating post data... ';
        $query = "UPDATE {$tableprefix}posts\n\t\t\t\t\t\t\tSET post_lastedit_user_ID = post_creator_user_ID,\n\t\t\t\t\t\t\t\t\tpost_datecreated = post_datestart";
        $DB->query($query);
        echo "OK.<br />\n";
        task_begin('Upgrading users table... ');
        $DB->query('UPDATE T_users
									  SET dateYMDhour = \'2000-01-01 00:00:00\'
									WHERE dateYMDhour = \'0000-00-00 00:00:00\'');
        $DB->query('ALTER TABLE T_users
							MODIFY COLUMN dateYMDhour DATETIME NOT NULL DEFAULT \'2000-01-01 00:00:00\',
							CHANGE COLUMN ID user_ID int(11) unsigned NOT NULL auto_increment,
							MODIFY COLUMN user_icq int(11) unsigned DEFAULT 0 NOT NULL,
							ADD COLUMN user_showonline tinyint(1) NOT NULL default 1 AFTER user_notify');
        task_end();
        set_upgrade_checkpoint('8860');
    }
    if ($old_db_version < 8900) {
        echo 'Setting new defaults... ';
        $query = 'INSERT INTO T_settings (set_name, set_value)
							VALUES
								( "reloadpage_timeout", "300" ),
								( "upload_enabled", "' . (isset($use_fileupload) ? (int) $use_fileupload : '1') . '" ),
								( "upload_allowedext", "' . (isset($fileupload_allowedtypes) ? $fileupload_allowedtypes : 'jpg gif png') . '" ),
								( "upload_maxkb", "' . (isset($fileupload_maxk) ? (int) $fileupload_maxk : '96') . '" )
							';
        $DB->query($query);
        // Replace "paged" mode with "posts" // note: moved to blogsettings in 2.0
        $DB->query('UPDATE T_settings
										SET set_value = "posts"
									WHERE set_name = "what_to_show"
									  AND set_value = "paged"');
        echo "OK.<br />\n";
        if (!isset($tableblogusers_isuptodate)) {
            // We have created the blogusers table before and it's already clean!
            echo 'Altering table for Blog-User permissions... ';
            $DB->query('ALTER TABLE T_coll_user_perms
										MODIFY COLUMN bloguser_blog_ID int(11) unsigned NOT NULL default 0,
										MODIFY COLUMN bloguser_user_ID int(11) unsigned NOT NULL default 0,
										ADD COLUMN bloguser_perm_media_upload tinyint NOT NULL default 0,
										ADD COLUMN bloguser_perm_media_browse tinyint NOT NULL default 0,
										ADD COLUMN bloguser_perm_media_change tinyint NOT NULL default 0');
            echo "OK.<br />\n";
        }
        task_begin('Altering comments table...');
        $DB->query('UPDATE T_comments
									  SET comment_date = \'2000-01-01 00:00:00\'
									WHERE comment_date = \'0000-00-00 00:00:00\'');
        $DB->query('ALTER TABLE T_comments
									MODIFY COLUMN comment_date DATETIME NOT NULL DEFAULT \'2000-01-01 00:00:00\',
									MODIFY COLUMN comment_post_ID		int(11) unsigned NOT NULL default 0');
        task_end();
        set_upgrade_checkpoint('8900');
    }
    if ($old_db_version < 9000) {
        echo 'Altering Posts to Categories table... ';
        $DB->query("ALTER TABLE T_postcats\n\t\t\t\t\t\t\t\t\tMODIFY COLUMN postcat_post_ID int(11) unsigned NOT NULL,\n\t\t\t\t\t\t\t\t\tMODIFY COLUMN postcat_cat_ID int(11) unsigned NOT NULL");
        echo "OK.<br />\n";
        echo 'Altering Categories table... ';
        $DB->query("ALTER TABLE T_categories\n\t\t\t\t\t\t\t\t\tMODIFY COLUMN cat_ID int(11) unsigned NOT NULL auto_increment,\n\t\t\t\t\t\t\t\t\tMODIFY COLUMN cat_parent_ID int(11) unsigned NULL,\n\t\t\t\t\t\t\t\t\tMODIFY COLUMN cat_blog_ID int(11) unsigned NOT NULL default 2");
        echo "OK.<br />\n";
        echo 'Altering Locales table... ';
        $DB->query('ALTER TABLE T_locales
									ADD loc_startofweek TINYINT UNSIGNED NOT NULL DEFAULT 1 AFTER loc_timefmt');
        echo "OK.<br />\n";
        if (!isset($tablegroups_isuptodate)) {
            // We have created the groups table before and it's already clean!
            echo 'Altering Groups table... ';
            $DB->query("ALTER TABLE T_groups\n\t\t\t\t\t\t\t\t\t\tADD COLUMN grp_perm_admin enum('none','hidden','visible') NOT NULL default 'visible' AFTER grp_name,\n\t\t\t\t\t\t\t\t\t\tADD COLUMN grp_perm_files enum('none','view','add','edit') NOT NULL default 'none'");
            echo "OK.<br />\n";
        }
        echo 'Creating table for Post Links... ';
        $DB->query("CREATE TABLE T_links (\n\t\t\t\t\t\t\t\t\tlink_ID               int(11) unsigned  not null AUTO_INCREMENT,\n\t\t\t\t\t\t\t\t\tlink_datecreated      datetime          not null,\n\t\t\t\t\t\t\t\t\tlink_datemodified     datetime          not null,\n\t\t\t\t\t\t\t\t\tlink_creator_user_ID  int(11) unsigned  not null,\n\t\t\t\t\t\t\t\t\tlink_lastedit_user_ID int(11) unsigned  not null,\n\t\t\t\t\t\t\t\t\tlink_item_ID          int(11) unsigned  NOT NULL,\n\t\t\t\t\t\t\t\t\tlink_dest_item_ID     int(11) unsigned  NULL,\n\t\t\t\t\t\t\t\t\tlink_file_ID          int(11) unsigned  NULL,\n\t\t\t\t\t\t\t\t\tlink_ltype_ID         int(11) unsigned  NOT NULL default 1,\n\t\t\t\t\t\t\t\t\tlink_external_url     VARCHAR(255)      NULL,\n\t\t\t\t\t\t\t\t\tlink_title            TEXT              NULL,\n\t\t\t\t\t\t\t\t\tPRIMARY KEY (link_ID),\n\t\t\t\t\t\t\t\t\tINDEX link_item_ID( link_item_ID ),\n\t\t\t\t\t\t\t\t\tINDEX link_dest_item_ID (link_dest_item_ID),\n\t\t\t\t\t\t\t\t\tINDEX link_file_ID (link_file_ID)\n\t\t\t\t\t\t\t\t)");
        echo "OK.<br />\n";
        echo 'Creating default Post Types... ';
        $DB->query("\n\t\t\tINSERT INTO {$tableprefix}posttypes ( ptyp_ID, ptyp_name )\n\t\t\tVALUES ( 1, 'Post' ),\n\t\t\t       ( 2, 'Link' )");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9000');
    }
    if ($old_db_version < 9100) {
        // 1.8 ALPHA
        echo 'Creating table for plugin events... ';
        $DB->query('
			CREATE TABLE T_pluginevents(
					pevt_plug_ID INT(11) UNSIGNED NOT NULL,
					pevt_event VARCHAR(40) NOT NULL,
					pevt_enabled TINYINT NOT NULL DEFAULT 1,
					PRIMARY KEY( pevt_plug_ID, pevt_event )
				)');
        echo "OK.<br />\n";
        echo 'Altering Links table... ';
        $DB->query('ALTER TABLE T_links
		             CHANGE link_item_ID link_itm_ID INT( 11 ) UNSIGNED NOT NULL,
		             CHANGE link_dest_item_ID link_dest_itm_ID INT( 11 ) UNSIGNED NULL');
        echo "OK.<br />\n";
        if ($old_db_version >= 9000) {
            // sess_agnt_ID used in Phoenix-Alpha
            echo 'Altering sessions table... ';
            $query = "\n\t\t\t\t\tALTER TABLE T_sessions\n\t\t\t\t\t DROP COLUMN sess_agnt_ID";
            $DB->query($query);
            echo "OK.<br />\n";
        }
        echo 'Creating table for file types... ';
        $DB->query('
				CREATE TABLE T_filetypes (
					ftyp_ID int(11) unsigned NOT NULL auto_increment,
					ftyp_extensions varchar(30) NOT NULL,
					ftyp_name varchar(30) NOT NULL,
					ftyp_mimetype varchar(50) NOT NULL,
					ftyp_icon varchar(20) default NULL,
					ftyp_viewtype varchar(10) NOT NULL,
					ftyp_allowed tinyint(1) NOT NULL default 0,
					PRIMARY KEY (ftyp_ID)
				)');
        echo "OK.<br />\n";
        echo 'Creating default file types... ';
        $DB->query("INSERT INTO T_filetypes\n\t\t\t\t(ftyp_ID, ftyp_extensions, ftyp_name, ftyp_mimetype, ftyp_icon, ftyp_viewtype, ftyp_allowed)\n\t\t\tVALUES\n\t\t\t\t(1, 'gif', 'GIF image', 'image/gif', 'image2.png', 'image', 1),\n\t\t\t\t(2, 'png', 'PNG image', 'image/png', 'image2.png', 'image', 1),\n\t\t\t\t(3, 'jpg jpeg', 'JPEG image', 'image/jpeg', 'image2.png', 'image', 1),\n\t\t\t\t(4, 'txt', 'Text file', 'text/plain', 'document.png', 'text', 1),\n\t\t\t\t(5, 'htm html', 'HTML file', 'text/html', 'html.png', 'browser', 0),\n\t\t\t\t(6, 'pdf', 'PDF file', 'application/pdf', 'pdf.png', 'browser', 1),\n\t\t\t\t(7, 'doc', 'Microsoft Word file', 'application/msword', 'doc.gif', 'external', 1),\n\t\t\t\t(8, 'xls', 'Microsoft Excel file', 'application/vnd.ms-excel', 'xls.gif', 'external', 1),\n\t\t\t\t(9, 'ppt', 'Powerpoint', 'application/vnd.ms-powerpoint', 'ppt.gif', 'external', 1),\n\t\t\t\t(10, 'pps', 'Slideshow', 'pps', 'pps.gif', 'external', 1),\n\t\t\t\t(11, 'zip', 'ZIP archive', 'application/zip', 'zip.gif', 'external', 1),\n\t\t\t\t(12, 'php php3 php4 php5 php6', 'PHP script', 'application/x-httpd-php', 'php.gif', 'text', 0),\n\t\t\t\t(13, 'css', 'Style sheet', 'text/css', '', 'text', 1)\n\t\t\t");
        echo "OK.<br />\n";
        echo 'Giving Administrator Group edit perms on files... ';
        $DB->query('UPDATE T_groups
		             SET grp_perm_files = "edit"
		             WHERE grp_ID = 1');
        // Later versions give 'all' on install, but we won't upgrade to that for security.
        echo "OK.<br />\n";
        echo 'Giving Administrator Group full perms on media for all blogs... ';
        $DB->query('UPDATE T_coll_group_perms
		             SET bloggroup_perm_media_upload = 1,
		                 bloggroup_perm_media_browse = 1,
		                 bloggroup_perm_media_change = 1
		             WHERE bloggroup_group_ID = 1');
        echo "OK.<br />\n";
        if ($old_db_version >= 9000) {
            // Uninstall all ALPHA (potentially incompatible) plugins
            echo 'Uninstalling all existing plugins... ';
            $DB->query('DELETE FROM T_plugins WHERE 1=1');
            echo "OK.<br />\n";
        }
        // NOTE: basic plugins get installed separatly for upgrade and install..
        set_upgrade_checkpoint('9100');
    }
    if ($old_db_version < 9190) {
        // 1.8 ALPHA (block #2)
        echo 'Altering Posts table... ';
        $DB->query("ALTER TABLE {$tableprefix}posts\n\t\t             CHANGE post_comments post_comment_status ENUM('disabled', 'open', 'closed') NOT NULL DEFAULT 'open'");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9190');
    }
    if ($old_db_version < 9192) {
        // 1.8 ALPHA (block #3) - The payload that db_delta() handled before
        // This is a fix, which broke upgrade to 1.8 (from 1.6) in MySQL strict mode (inserted after 1.8 got released!):
        if ($DB->get_row('SHOW COLUMNS FROM T_hitlog LIKE "hit_referer_type"')) {
            // a niiiiiiiice extra check :p
            task_begin('Deleting all "spam" hitlog entries... ');
            $DB->query('
					DELETE FROM T_hitlog
					 WHERE hit_referer_type = "spam"');
            task_end();
        }
        task_begin('Upgrading users table... ');
        $DB->query('ALTER TABLE T_users
										CHANGE COLUMN user_firstname user_firstname varchar(50) NULL,
										CHANGE COLUMN user_lastname user_lastname varchar(50) NULL,
										CHANGE COLUMN user_nickname user_nickname varchar(50) NULL,
										CHANGE COLUMN user_icq user_icq int(11) unsigned NULL,
										CHANGE COLUMN user_email user_email varchar(255) NOT NULL,
										CHANGE COLUMN user_url user_url varchar(255) NULL,
										CHANGE COLUMN user_ip user_ip varchar(15) NULL,
										CHANGE COLUMN user_domain user_domain varchar(200) NULL,
										CHANGE COLUMN user_browser user_browser varchar(200) NULL,
										CHANGE COLUMN user_aim user_aim varchar(50) NULL,
										CHANGE COLUMN user_msn user_msn varchar(100) NULL,
										CHANGE COLUMN user_yim user_yim varchar(50) NULL,
										ADD COLUMN user_allow_msgform TINYINT NOT NULL DEFAULT \'1\' AFTER user_idmode,
										ADD COLUMN user_validated TINYINT(1) NOT NULL DEFAULT 0 AFTER user_grp_ID');
        task_end();
        task_begin('Creating blog settings...');
        $DB->query('CREATE TABLE T_coll_settings (
															cset_coll_ID INT(11) UNSIGNED NOT NULL,
															cset_name    VARCHAR( 30 ) NOT NULL,
															cset_value   VARCHAR( 255 ) NULL,
															PRIMARY KEY ( cset_coll_ID, cset_name )
											)');
        task_end();
        set_upgrade_checkpoint('9192');
    }
    if ($old_db_version < 9195) {
        task_begin('Upgrading posts table... ');
        $DB->query('ALTER TABLE ' . $tableprefix . 'posts
										CHANGE COLUMN post_content post_content         text NULL,
										CHANGE COLUMN post_url post_url              		VARCHAR(255) NULL DEFAULT NULL,
										CHANGE COLUMN post_renderers post_renderers     TEXT NOT NULL');
        task_end();
        task_begin('Upgrading comments table... ');
        $DB->query('ALTER TABLE T_comments
										CHANGE COLUMN comment_author_email comment_author_email varchar(255) NULL,
										CHANGE COLUMN comment_author_url comment_author_url varchar(255) NULL,
										ADD COLUMN comment_spam_karma TINYINT NULL AFTER comment_karma,
										ADD COLUMN comment_allow_msgform TINYINT NOT NULL DEFAULT 0 AFTER comment_spam_karma');
        task_end();
        set_upgrade_checkpoint('9195');
    }
    if ($old_db_version < 9200) {
        task_begin('Upgrading hitlog table... ');
        $DB->query('ALTER TABLE T_hitlog
										CHANGE COLUMN hit_referer_type hit_referer_type   ENUM(\'search\',\'blacklist\',\'referer\',\'direct\') NOT NULL,
										ADD COLUMN hit_agnt_ID        INT UNSIGNED NULL AFTER hit_remote_addr');
        task_end();
        task_begin('Upgrading post links table... ');
        $DB->query('ALTER TABLE T_links
										ADD INDEX link_itm_ID( link_itm_ID ),
										ADD INDEX link_dest_itm_ID (link_dest_itm_ID)');
        task_end();
        task_begin('Upgrading plugins table... ');
        $DB->query('ALTER TABLE T_plugins
										CHANGE COLUMN plug_priority plug_priority        TINYINT NOT NULL default 50,
										ADD COLUMN plug_code            VARCHAR(32) NULL AFTER plug_classname,
										ADD COLUMN plug_apply_rendering ENUM( \'stealth\', \'always\', \'opt-out\', \'opt-in\', \'lazy\', \'never\' ) NOT NULL DEFAULT \'never\' AFTER plug_code,
										ADD COLUMN plug_version         VARCHAR(42) NOT NULL default \'0\' AFTER plug_apply_rendering,
										ADD COLUMN plug_status          ENUM( \'enabled\', \'disabled\', \'needs_config\', \'broken\' ) NOT NULL AFTER plug_version,
										ADD COLUMN plug_spam_weight     TINYINT UNSIGNED NOT NULL DEFAULT 1 AFTER plug_status');
        $DB->query('ALTER TABLE T_plugins
										ADD UNIQUE plug_code( plug_code ),
										ADD INDEX plug_status( plug_status )');
        task_end();
        task_begin('Creating plugin settings table... ');
        $DB->query('CREATE TABLE T_pluginsettings (
															pset_plug_ID INT(11) UNSIGNED NOT NULL,
															pset_name VARCHAR( 30 ) NOT NULL,
															pset_value TEXT NULL,
															PRIMARY KEY ( pset_plug_ID, pset_name )
											)');
        task_end();
        task_begin('Creating plugin user settings table... ');
        $DB->query('CREATE TABLE T_pluginusersettings (
															puset_plug_ID INT(11) UNSIGNED NOT NULL,
															puset_user_ID INT(11) UNSIGNED NOT NULL,
															puset_name VARCHAR( 30 ) NOT NULL,
															puset_value TEXT NULL,
															PRIMARY KEY ( puset_plug_ID, puset_user_ID, puset_name )
											)');
        task_end();
        task_begin('Creating scheduled tasks table... ');
        $DB->query('CREATE TABLE T_cron__task(
												 ctsk_ID              int(10) unsigned      not null AUTO_INCREMENT,
												 ctsk_start_datetime  datetime              not null,
												 ctsk_repeat_after    int(10) unsigned,
												 ctsk_name            varchar(50)           not null,
												 ctsk_controller      varchar(50)           not null,
												 ctsk_params          text,
												 primary key (ctsk_ID)
											)');
        task_end();
        task_begin('Creating cron log table... ');
        $DB->query('CREATE TABLE T_cron__log(
															 clog_ctsk_ID              int(10) unsigned   not null,
															 clog_realstart_datetime   datetime           not null,
															 clog_realstop_datetime    datetime,
															 clog_status               enum(\'started\',\'finished\',\'error\',\'timeout\') not null default \'started\',
															 clog_messages             text,
															 primary key (clog_ctsk_ID)
											)');
        task_end();
        task_begin('Upgrading blogs table... ');
        // blog_allowpingbacks is "DEFAULT 1" in the 0.9.0.11 dump.. - changed in 0.9.2?!
        $DB->query('ALTER TABLE T_blogs
										ALTER COLUMN blog_allowpingbacks SET DEFAULT 0,
    								CHANGE COLUMN blog_media_subdir blog_media_subdir VARCHAR( 255 ) NULL,
										CHANGE COLUMN blog_media_fullpath blog_media_fullpath VARCHAR( 255 ) NULL,
										CHANGE COLUMN blog_media_url blog_media_url VARCHAR( 255 ) NULL');
        task_end();
        set_upgrade_checkpoint('9200');
        // at 1.8 "Summer Beta" release
    }
    // ____________________________ 1.9: ____________________________
    if ($old_db_version < 9290) {
        echo 'Post-fix hit_referer_type == NULL... ';
        // If you've upgraded from 1.6 to 1.8 and it did not break because of strict mode, there are now NULL values for what "spam" was:
        $DB->query('
					DELETE FROM T_hitlog
					 WHERE hit_referer_type IS NULL');
        echo "OK.<br />\n";
        echo 'Marking administrator accounts as validated... ';
        $DB->query('
				UPDATE T_users
				   SET user_validated = 1
				 WHERE user_grp_ID = 1');
        echo "OK.<br />\n";
        echo 'Converting auto_prune_stats setting... ';
        $old_auto_prune_stats = $DB->get_var('
				SELECT set_value
				  FROM T_settings
				 WHERE set_name = "auto_prune_stats"');
        if (!is_null($old_auto_prune_stats) && $old_auto_prune_stats < 1) {
            // This means it has been disabled before, so set auto_prune_stats_mode to "off"!
            $DB->query('
					REPLACE INTO T_settings ( set_name, set_value )
					 VALUES ( "auto_prune_stats_mode", "off" )');
        }
        echo "OK.<br />\n";
        echo 'Converting time_difference from hours to seconds... ';
        $DB->query('UPDATE T_settings SET set_value = set_value*3600 WHERE set_name = "time_difference"');
        echo "OK.<br />\n";
        echo 'Updating hitlog capabilities... ';
        $DB->query('
				ALTER TABLE ' . $tableprefix . 'useragents ADD INDEX agnt_type ( agnt_type )');
        $DB->query('
				ALTER TABLE T_hitlog
				  CHANGE COLUMN hit_referer_type hit_referer_type ENUM(\'search\',\'blacklist\',\'referer\',\'direct\',\'self\',\'admin\') NOT NULL');
        echo "OK.<br />\n";
        echo 'Updating plugin capabilities... ';
        $DB->query('
				ALTER TABLE T_plugins
					MODIFY COLUMN plug_status ENUM( \'enabled\', \'disabled\', \'needs_config\', \'broken\' ) NOT NULL');
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9290');
    }
    if ($old_db_version < 9300) {
        // This can be so long, it needs its own checkpoint protected block in case of failure
        echo 'Updating hitlog indexes... ';
        $DB->query('
				ALTER TABLE T_hitlog
				  ADD INDEX hit_agnt_ID        ( hit_agnt_ID ),
				  ADD INDEX hit_uri            ( hit_uri ),
				  ADD INDEX hit_referer_dom_ID ( hit_referer_dom_ID )
				');
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9300');
    }
    if ($old_db_version < 9310) {
        echo 'Updating basedomains... ';
        $DB->query('
				UPDATE T_basedomains
				   SET dom_status = "unknown"');
        // someone has filled this up with junk blacklists before
        $DB->query('
				ALTER TABLE T_basedomains  ADD INDEX dom_type (dom_type)');
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9310');
    }
    if ($old_db_version < 9315) {
        echo 'Altering locales table... ';
        $DB->query("ALTER TABLE T_locales CHANGE COLUMN loc_datefmt loc_datefmt varchar(20) NOT NULL default 'y-m-d'");
        $DB->query("ALTER TABLE T_locales CHANGE COLUMN loc_timefmt loc_timefmt varchar(20) NOT NULL default 'H:i:s'");
        echo "OK.<br />\n";
        echo 'Creating item prerendering cache table... ';
        $DB->query("\n\t\t\t\tCREATE TABLE {$tableprefix}item__prerendering(\n\t\t\t\t\titpr_itm_ID                   INT(11) UNSIGNED NOT NULL,\n\t\t\t\t\titpr_format                   ENUM('htmlbody', 'entityencoded', 'xml', 'text') NOT NULL,\n\t\t\t\t\titpr_renderers                TEXT NOT NULL,\n\t\t\t\t\titpr_content_prerendered      TEXT NULL,\n\t\t\t\t\titpr_datemodified             TIMESTAMP NOT NULL,\n\t\t\t\t\tPRIMARY KEY (itpr_itm_ID, itpr_format)\n\t\t\t\t)");
        echo "OK.<br />\n";
        echo 'Altering plugins table... ';
        $DB->query("ALTER TABLE T_plugins ADD COLUMN plug_name            VARCHAR(255) NULL default NULL AFTER plug_version");
        $DB->query("ALTER TABLE T_plugins ADD COLUMN plug_shortdesc       VARCHAR(255) NULL default NULL AFTER plug_name");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9315');
    }
    if ($old_db_version < 9320) {
        // Dropping hit_datetime because it's very slow on INSERT (dh)
        // This can be so long, it needs its own checkpoint protected block in case of failure
        if (db_index_exists('T_hitlog', 'hit_datetime')) {
            // only drop, if it still exists (may have been removed manually)
            echo 'Updating hitlog indexes... ';
            $DB->query('
					ALTER TABLE T_hitlog
						DROP INDEX hit_datetime
					');
            echo "OK.<br />\n";
        }
        set_upgrade_checkpoint('9320');
    }
    if ($old_db_version < 9326) {
        echo 'Removing obsolete settings... ';
        $DB->query('DELETE FROM T_settings WHERE set_name = "upload_allowedext"');
        echo "OK.<br />\n";
        echo 'Updating blogs... ';
        db_drop_col('T_blogs', 'blog_allowpingbacks');
        // Remove and transform obsolete fields blog_pingb2evonet, blog_pingtechnorati, blog_pingweblogs, blog_pingblodotgs
        if (db_cols_exist('T_blogs', array('blog_pingb2evonet', 'blog_pingtechnorati', 'blog_pingweblogs', 'blog_pingblodotgs'))) {
            foreach ($DB->get_results('
					SELECT blog_ID, blog_pingb2evonet, blog_pingtechnorati, blog_pingweblogs, blog_pingblodotgs
						FROM T_blogs') as $row) {
                $ping_plugins = $DB->get_var('SELECT cset_value FROM T_coll_settings WHERE cset_coll_ID = ' . $row->blog_ID . ' AND cset_name = "ping_plugins"');
                $ping_plugins = explode(',', $ping_plugins);
                if ($row->blog_pingb2evonet) {
                    $ping_plugins[] = 'ping_b2evonet';
                }
                if ($row->blog_pingtechnorati || $row->blog_pingweblogs || $row->blog_pingblodotgs) {
                    // if either one of the previous pingers was enabled, add ping-o-matic:
                    $ping_plugins[] = 'ping_pingomatic';
                }
                // Insert transformed/generated ping plugins collection setting:
                $ping_plugins = array_unique($ping_plugins);
                $DB->query('REPLACE INTO T_coll_settings
						( cset_coll_ID, cset_name, cset_value )
						VALUES ( ' . $row->blog_ID . ', "ping_plugins", "' . implode(',', $ping_plugins) . '" )');
            }
            $DB->query('ALTER TABLE T_blogs
					DROP COLUMN blog_pingb2evonet,
					DROP COLUMN blog_pingtechnorati,
					DROP COLUMN blog_pingweblogs,
					DROP COLUMN blog_pingblodotgs');
        }
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9326');
    }
    if ($old_db_version < 9328) {
        echo 'Updating posts... ';
        db_add_col("{$tableprefix}posts", 'post_notifications_status', 'ENUM("noreq","todo","started","finished") NOT NULL DEFAULT "noreq" AFTER post_flags');
        db_add_col("{$tableprefix}posts", 'post_notifications_ctsk_ID', 'INT(10) unsigned NULL DEFAULT NULL AFTER post_notifications_status');
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9328');
    }
    if ($old_db_version < 9330) {
        if (db_col_exists("{$tableprefix}posts", 'post_flags')) {
            echo 'Updating post notifications... ';
            $DB->query("\n\t\t\t\tUPDATE {$tableprefix}posts\n\t\t\t\t\t SET post_notifications_status = 'finished'\n\t\t\t\t WHERE post_flags LIKE '%pingsdone%'");
            db_drop_col("{$tableprefix}posts", 'post_flags');
            echo "OK.<br />\n";
        }
        set_upgrade_checkpoint('9330');
    }
    if ($old_db_version < 9340) {
        echo 'Removing duplicate post link indexes... ';
        if (db_index_exists('T_links', 'link_item_ID')) {
            // only drop, if it still exists (may have been removed manually)
            $DB->query('
					ALTER TABLE T_links
						DROP INDEX link_item_ID
					');
        }
        if (db_index_exists('T_links', 'link_dest_item_ID')) {
            // only drop, if it still exists (may have been removed manually)
            $DB->query('
					ALTER TABLE T_links
						DROP INDEX link_dest_item_ID
					');
        }
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9340');
    }
    // ____________________________ 1.10: ____________________________
    if ($old_db_version < 9345) {
        echo 'Updating post table... ';
        $DB->query("ALTER TABLE {$tableprefix}posts CHANGE COLUMN post_content post_content MEDIUMTEXT NULL");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9345');
    }
    if ($old_db_version < 9346) {
        echo 'Updating prerendering table... ';
        $DB->query("ALTER TABLE {$tableprefix}item__prerendering CHANGE COLUMN itpr_content_prerendered itpr_content_prerendered MEDIUMTEXT NULL");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9346');
    }
    if ($old_db_version < 9348) {
        echo 'Updating sessions table... ';
        $DB->query('ALTER TABLE T_sessions CHANGE COLUMN sess_data sess_data MEDIUMBLOB DEFAULT NULL');
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9348');
    }
    if ($old_db_version < 9350) {
        echo 'Updating hitlog table... ';
        $DB->query('ALTER TABLE T_hitlog CHANGE COLUMN hit_referer_type hit_referer_type   ENUM(\'search\',\'blacklist\',\'spam\',\'referer\',\'direct\',\'self\',\'admin\') NOT NULL');
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9350');
    }
    // TODO: "If a user has permission to edit a blog, he should be able to put files in the media folder for that blog." - see http://forums.b2evolution.net/viewtopic.php?p=36417#36417
    /*
    // blueyed>> I've came up with the following, but it's too generic IMHO
    if( $old_db_version < 9300 )
    {
    	echo 'Setting automatic media perms on blogs (members can upload)... ';
    	$users = $DB->query( '
    			UPDATE T_users
    			   SET bloguser_perm_media_upload = 1
    			 WHERE bloguser_ismember = 1' );
    	echo "OK.<br />\n";
    }
    */
    // ____________________________ 2.0: ____________________________
    if ($old_db_version < 9406) {
        echo 'Updating chapter url names... ';
        $DB->query('
			ALTER TABLE T_categories
				ADD COLUMN cat_urlname VARCHAR(255) NOT NULL');
        // Create cat_urlname from cat_name:
        // TODO: Also use it for cafelog upgrade.
        load_funcs('locales/_charset.funcs.php');
        foreach ($DB->get_results('SELECT cat_ID, cat_name FROM T_categories') as $cat) {
            $cat_name = trim($cat->cat_name);
            if (strlen($cat_name)) {
                // TODO: dh> pass locale (useful for transliteration). From main blog?
                $cat_urlname = urltitle_validate('', $cat_name, $cat->cat_ID, false, 'cat_urlname', 'cat_ID', 'T_categories');
            } else {
                $cat_urlname = 'c' . $cat->cat_ID;
            }
            $DB->query('
				UPDATE T_categories
					 SET cat_urlname = ' . $DB->quote($cat_urlname) . '
				 WHERE cat_ID = ' . $cat->cat_ID);
        }
        $DB->query('
			ALTER TABLE T_categories
				ADD UNIQUE cat_urlname ( cat_urlname )');
        echo "OK.<br />\n";
        echo 'Updating Settings... ';
        $DB->query('
      UPDATE T_settings
         SET set_value = "disabled"
       WHERE set_name = "links_extrapath"
         AND set_value = 0');
        $DB->query('
      UPDATE T_settings
         SET set_value = "ymd"
       WHERE set_name = "links_extrapath"
         AND set_value <> 0');
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9406');
    }
    if ($old_db_version < 9407) {
        echo 'Moving general settings to blog settings... ';
        $DB->query('REPLACE INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
		             SELECT blog_ID, set_name, set_value
									 FROM T_blogs, T_settings
									WHERE set_name = "posts_per_page"
									   OR set_name = "what_to_show"
									   OR set_name = "archive_mode"');
        $DB->query('DELETE FROM T_settings
									WHERE set_name = "posts_per_page"
									   OR set_name = "what_to_show"
									   OR set_name = "archive_mode"');
        echo "OK.<br />\n";
        echo 'Upgrading blogs table... ';
        $query = "ALTER TABLE T_blogs\n\t\t\t\t\t\t\tDROP COLUMN blog_force_skin";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading groups table... ';
        $query = "ALTER TABLE T_groups\n\t\t\t\t\t\t\tCHANGE COLUMN grp_perm_files grp_perm_files enum('none','view','add','edit','all') NOT NULL default 'none'";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading files table... ';
        $query = "ALTER TABLE T_files\n\t\t\t\t\t\t\tCHANGE COLUMN file_root_type file_root_type enum('absolute','user','group','collection','skins') not null default 'absolute'";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Updating file types... ';
        // Only change this if it's close enough to a default install (non customized)
        $DB->query("UPDATE T_filetypes\n\t\t\t\t\t\t\t\t\t\tSET ftyp_viewtype = 'text'\n\t\t\t\t\t\t\t\t\tWHERE ftyp_ID = 12\n\t\t\t\t\t\t\t\t\t\tAND ftyp_extensions = 'php php3 php4 php5 php6'\n\t\t\t\t\t\t\t\t\t\tAND ftyp_mimetype ='application/x-httpd-php'\n\t\t\t\t\t\t\t\t\t\tAND ftyp_icon = 'php.gif'");
        echo "OK.<br />\n";
        echo 'Remove obsolete user settings... ';
        $DB->query('DELETE FROM ' . $tableprefix . 'usersettings
									WHERE uset_name = "plugins_disp_avail"');
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9407');
    }
    if ($old_db_version < 9408) {
        echo 'Creating skins table... ';
        $DB->query('CREATE TABLE T_skins__skin (
              skin_ID      int(10) unsigned      NOT NULL auto_increment,
              skin_name    varchar(32)           NOT NULL,
              skin_type    enum(\'normal\',\'feed\') NOT NULL default \'normal\',
              skin_folder  varchar(32)           NOT NULL,
              PRIMARY KEY skin_ID (skin_ID),
              UNIQUE skin_folder( skin_folder ),
              KEY skin_name( skin_name )
            )');
        echo "OK.<br />\n";
        echo 'Creating skin containers table... ';
        $DB->query('CREATE TABLE T_skins__container (
              sco_skin_ID   int(10) unsigned      NOT NULL,
              sco_name      varchar(40)           NOT NULL,
              PRIMARY KEY (sco_skin_ID, sco_name)
            )');
        echo "OK.<br />\n";
        echo 'Creating widgets table... ';
        $DB->query('CREATE TABLE T_widget (
 						wi_ID					INT(10) UNSIGNED auto_increment,
						wi_coll_ID    INT(11) UNSIGNED NOT NULL,
						wi_sco_name   VARCHAR( 40 ) NOT NULL,
						wi_order			INT(10) UNSIGNED NOT NULL,
						wi_type       ENUM( \'core\', \'plugin\' ) NOT NULL DEFAULT \'core\',
						wi_code       VARCHAR(32) NOT NULL,
						wi_params     TEXT NULL,
						PRIMARY KEY ( wi_ID ),
						UNIQUE wi_order( wi_coll_ID, wi_sco_name, wi_order )
          )');
        echo "OK.<br />\n";
        install_basic_skins(false);
        echo 'Updating blogs table... ';
        $DB->query('ALTER TABLE T_blogs
								 ALTER COLUMN blog_allowtrackbacks SET DEFAULT 0,
									DROP COLUMN blog_default_skin,
									 ADD COLUMN blog_owner_user_ID   int(11) unsigned NOT NULL default 1 AFTER blog_name,
									 ADD COLUMN blog_skin_ID INT(10) UNSIGNED NOT NULL DEFAULT 1 AFTER blog_allowusercss');
        echo "OK.<br />\n";
        install_basic_widgets($old_db_version);
        set_upgrade_checkpoint('9408');
    }
    if ($old_db_version < 9409) {
        // Upgrade the blog access types:
        echo 'Updating blogs access types... ';
        $DB->query('UPDATE T_blogs
										SET blog_access_type = "absolute"
									WHERE blog_siteurl LIKE "http://%"
									   OR blog_siteurl LIKE "https://%"');
        $DB->query('UPDATE T_blogs
										SET blog_access_type = "relative",
												blog_siteurl = CONCAT( blog_siteurl, blog_stub )
									WHERE blog_access_type = "stub"');
        db_drop_col('T_blogs', 'blog_stub');
        echo "OK.<br />\n";
        echo 'Updating columns... ';
        $DB->query("ALTER TABLE T_groups CHANGE COLUMN grp_perm_stats grp_perm_stats enum('none','user','view','edit') NOT NULL default 'none'");
        $DB->query("ALTER TABLE T_coll_user_perms CHANGE COLUMN bloguser_perm_poststatuses bloguser_perm_poststatuses set('published','deprecated','protected','private','draft','redirected') NOT NULL default ''");
        $DB->query("ALTER TABLE T_coll_group_perms CHANGE COLUMN bloggroup_perm_poststatuses bloggroup_perm_poststatuses set('published','deprecated','protected','private','draft','redirected') NOT NULL default ''");
        $DB->query("ALTER TABLE {$tableprefix}posts CHANGE COLUMN post_status post_status enum('published','deprecated','protected','private','draft','redirected') NOT NULL default 'published'");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9409');
    }
    if ($old_db_version < 9410) {
        echo 'Updating columns... ';
        $DB->query("ALTER TABLE T_comments CHANGE COLUMN comment_status comment_status ENUM('published','deprecated','protected','private','draft','redirected') DEFAULT 'published' NOT NULL");
        $DB->query("ALTER TABLE T_sessions CHANGE COLUMN sess_data sess_data MEDIUMBLOB DEFAULT NULL");
        $DB->query("ALTER TABLE T_hitlog CHANGE COLUMN hit_referer_type hit_referer_type ENUM('search','blacklist','spam','referer','direct','self','admin') NOT NULL");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9410');
    }
    if ($old_db_version < 9411) {
        echo 'Adding default Post Types... ';
        $DB->query("\n\t\t\tREPLACE INTO {$tableprefix}posttypes ( ptyp_ID, ptyp_name )\n\t\t\tVALUES ( 1000, 'Page' ),\n\t\t\t\t\t\t ( 2000, 'Reserved' ),\n\t\t\t\t\t\t ( 3000, 'Reserved' ),\n\t\t\t\t\t\t ( 4000, 'Reserved' ),\n\t\t\t\t\t\t ( 5000, 'Reserved' ) ");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9411');
    }
    if ($old_db_version < 9412) {
        echo 'Adding field for post excerpts... ';
        $DB->query("ALTER TABLE {$tableprefix}posts ADD COLUMN post_excerpt  text NULL AFTER post_content");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9412');
    }
    if ($old_db_version < 9414) {
        echo "Renaming tables...";
        $DB->query("RENAME TABLE {$tableprefix}item__prerendering TO T_items__prerendering");
        $DB->query("RENAME TABLE {$tableprefix}poststatuses TO T_items__status");
        $DB->query("RENAME TABLE {$tableprefix}posttypes TO T_items__type");
        $DB->query("RENAME TABLE {$tableprefix}posts TO T_items__item");
        echo "OK.<br />\n";
        echo "Creating Tag tables...";
        $DB->query("CREATE TABLE T_items__tag (\n\t\t      tag_ID   int(11) unsigned not null AUTO_INCREMENT,\n\t\t      tag_name varchar(50) not null,\n\t\t      primary key (tag_ID),\n\t\t      UNIQUE tag_name( tag_name )\n\t\t    )");
        $DB->query("CREATE TABLE T_items__itemtag (\n\t\t      itag_itm_ID int(11) unsigned NOT NULL,\n\t\t      itag_tag_ID int(11) unsigned NOT NULL,\n\t\t      PRIMARY KEY (itag_itm_ID, itag_tag_ID),\n\t\t      UNIQUE tagitem ( itag_tag_ID, itag_itm_ID )\n\t\t    )");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9414');
    }
    if ($old_db_version < 9416) {
        echo "Updating blogs table...";
        $DB->query("ALTER TABLE T_blogs\n\t\t\t\t\t\t\t\t\tADD COLUMN blog_advanced_perms  TINYINT(1) NOT NULL default 0 AFTER blog_owner_user_ID,\n\t\t\t\t\t\t\t\t\tDROP COLUMN blog_staticfilename");
        $DB->query("UPDATE T_blogs\n\t\t\t\t\t\t\t\t\t  SET blog_advanced_perms = 1");
        echo "OK.<br />\n";
        echo "Additionnal blog permissions...";
        $DB->query("ALTER TABLE T_coll_user_perms\n\t\t\t\t\t\t\t\t\tADD COLUMN bloguser_perm_admin tinyint NOT NULL default 0 AFTER bloguser_perm_properties,\n\t\t\t\t\t\t\t\t\tADD COLUMN bloguser_perm_edit  ENUM('no','own','lt','le','all','redirected') NOT NULL default 'no' AFTER bloguser_perm_poststatuses");
        $DB->query("ALTER TABLE T_coll_group_perms\n\t\t\t\t\t\t\t\t\tADD COLUMN bloggroup_perm_admin tinyint NOT NULL default 0 AFTER bloggroup_perm_properties,\n\t\t\t\t\t\t\t\t\tADD COLUMN bloggroup_perm_edit  ENUM('no','own','lt','le','all','redirected') NOT NULL default 'no' AFTER bloggroup_perm_poststatuses");
        // Preserve full admin perms:
        $DB->query("UPDATE T_coll_user_perms\n\t\t\t\t\t\t\t\t\t\tSET bloguser_perm_admin = 1\n\t\t\t\t\t\t\t\t\tWHERE bloguser_perm_properties <> 0");
        $DB->query("UPDATE T_coll_group_perms\n\t\t\t\t\t\t\t\t\t\tSET bloggroup_perm_admin = 1\n\t\t\t\t\t\t\t\t\tWHERE bloggroup_perm_properties <> 0");
        // Preserve full edit perms:
        $DB->query("UPDATE T_coll_user_perms\n\t\t\t\t\t\t\t\t\t\tSET bloguser_perm_edit = 'all'");
        $DB->query("UPDATE T_coll_group_perms\n\t\t\t\t\t\t\t\t\t\tSET bloggroup_perm_edit = 'all'");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9416');
    }
    if ($old_db_version < 9500) {
        task_begin('Normalizing columns...');
        $DB->query('ALTER TABLE T_blogs
										ALTER COLUMN blog_shortname SET DEFAULT \'\',
										ALTER COLUMN blog_tagline SET DEFAULT \'\',
										CHANGE COLUMN blog_description blog_description     varchar(250) NULL default \'\',
										ALTER COLUMN blog_siteurl SET DEFAULT \'\'');
        task_end();
        task_begin('Normalizing dates...');
        $DB->query('UPDATE T_users
										SET dateYMDhour = \'2000-01-01 00:00:00\'
									WHERE dateYMDhour = \'0000-00-00 00:00:00\'');
        $DB->query('ALTER TABLE T_users
									MODIFY COLUMN dateYMDhour DATETIME NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('UPDATE T_comments
										SET comment_date = \'2000-01-01 00:00:00\'
									WHERE comment_date = \'0000-00-00 00:00:00\'');
        $DB->query('ALTER TABLE T_comments
									MODIFY COLUMN comment_date DATETIME NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        task_end();
        task_begin('Normalizing cron jobs...');
        $DB->query('UPDATE T_cron__task
										SET ctsk_controller = REPLACE(ctsk_controller, "cron/_", "cron/jobs/_" )
									WHERE ctsk_controller LIKE "cron/_%"');
        task_end();
        task_begin('Extending comments table...');
        $DB->query('ALTER TABLE T_comments
									ADD COLUMN comment_rating     TINYINT(1) NULL DEFAULT NULL AFTER comment_content,
									ADD COLUMN comment_featured   TINYINT(1) NOT NULL DEFAULT 0 AFTER comment_rating,
									ADD COLUMN comment_nofollow   TINYINT(1) NOT NULL DEFAULT 1 AFTER comment_featured;');
        task_end();
        set_upgrade_checkpoint('9500');
    }
    if ($old_db_version < 9600) {
        // 2.2.0
        task_begin('Creating global cache table...');
        $DB->query('CREATE TABLE T_global__cache (
							      cach_name VARCHAR( 30 ) NOT NULL ,
							      cach_cache MEDIUMBLOB NULL ,
							      PRIMARY KEY ( cach_name )
							    )');
        task_end();
        task_begin('Altering posts table...');
        $DB->query('ALTER TABLE T_items__item
										MODIFY COLUMN post_datestart DATETIME NOT NULL DEFAULT \'2000-01-01 00:00:00\',
										MODIFY COLUMN post_datemodified DATETIME NOT NULL DEFAULT \'2000-01-01 00:00:00\',
										ADD COLUMN post_order    float NULL AFTER post_priority,
										ADD COLUMN post_featured tinyint(1) NOT NULL DEFAULT 0 AFTER post_order');
        $DB->query('ALTER TABLE T_items__item
										ADD INDEX post_order( post_order )');
        task_end();
        set_upgrade_checkpoint('9600');
    }
    if ($old_db_version < 9700) {
        // 2.3.2
        echo 'Creating PodCast Post Type... ';
        $DB->query("\n\t\t\tREPLACE INTO T_items__type ( ptyp_ID, ptyp_name )\n\t\t\tVALUES ( 2000, 'Podcast' )");
        echo "OK.<br />\n";
        // 2.4.0
        echo 'Adding additional group permissions... ';
        $DB->query("\n\t      ALTER TABLE T_groups\n\t\t\t\t\tADD COLUMN grp_perm_bypass_antispam         TINYINT(1)  NOT NULL DEFAULT 0        AFTER grp_perm_blogs,\n\t\t\t\t\tADD COLUMN grp_perm_xhtmlvalidation         VARCHAR(10) NOT NULL default 'always' AFTER grp_perm_bypass_antispam,\n\t\t\t\t\tADD COLUMN grp_perm_xhtmlvalidation_xmlrpc  VARCHAR(10) NOT NULL default 'always' AFTER grp_perm_xhtmlvalidation,\n\t\t\t\t\tADD COLUMN grp_perm_xhtml_css_tweaks        TINYINT(1)  NOT NULL DEFAULT 0        AFTER grp_perm_xhtmlvalidation_xmlrpc,\n      \t\tADD COLUMN grp_perm_xhtml_iframes           TINYINT(1)  NOT NULL DEFAULT 0        AFTER grp_perm_xhtml_css_tweaks,\n      \t\tADD COLUMN grp_perm_xhtml_javascript        TINYINT(1)  NOT NULL DEFAULT 0        AFTER grp_perm_xhtml_iframes,\n\t\t\t\t\tADD COLUMN grp_perm_xhtml_objects           TINYINT(1)  NOT NULL DEFAULT 0        AFTER grp_perm_xhtml_javascript ");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9700');
    }
    if ($old_db_version < 9800) {
        // 2.5.0
        echo 'Upgrading blogs table... ';
        db_drop_col('T_blogs', 'blog_commentsexpire');
        echo "OK.<br />\n";
        echo 'Upgrading items table... ';
        $DB->query("ALTER TABLE T_items__item\n\t\t\tCHANGE COLUMN post_urltitle post_urltitle VARCHAR(210) NULL DEFAULT NULL,\n\t\t\tCHANGE COLUMN post_order    post_order DOUBLE NULL,\n\t\t\tADD COLUMN post_titletag  VARCHAR(255) NULL DEFAULT NULL AFTER post_urltitle,\n\t\t\tADD COLUMN post_double1   DOUBLE NULL COMMENT 'Custom double value 1' AFTER post_priority,\n\t\t\tADD COLUMN post_double2   DOUBLE NULL COMMENT 'Custom double value 2' AFTER post_double1,\n\t\t\tADD COLUMN post_double3   DOUBLE NULL COMMENT 'Custom double value 3' AFTER post_double2,\n\t\t\tADD COLUMN post_double4   DOUBLE NULL COMMENT 'Custom double value 4' AFTER post_double3,\n\t\t\tADD COLUMN post_double5   DOUBLE NULL COMMENT 'Custom double value 5' AFTER post_double4,\n\t\t\tADD COLUMN post_varchar1  VARCHAR(255) NULL COMMENT 'Custom varchar value 1' AFTER post_double5,\n\t\t\tADD COLUMN post_varchar2  VARCHAR(255) NULL COMMENT 'Custom varchar value 2' AFTER post_varchar1,\n\t\t\tADD COLUMN post_varchar3  VARCHAR(255) NULL COMMENT 'Custom varchar value 3' AFTER post_varchar2");
        echo "OK.<br />\n";
        echo 'Creating keyphrase table... ';
        $query = "CREATE TABLE T_track__keyphrase (\n            keyp_ID      INT UNSIGNED NOT NULL AUTO_INCREMENT,\n            keyp_phrase  VARCHAR( 255 ) NOT NULL,\n            PRIMARY KEY        ( keyp_ID ),\n            UNIQUE keyp_phrase ( keyp_phrase )\n          )";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading hitlog table... ';
        evo_flush();
        $query = "ALTER TABLE T_hitlog\n\t\t\t CHANGE COLUMN hit_ID hit_ID              INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,\n\t\t\t CHANGE COLUMN hit_datetime hit_datetime  DATETIME NOT NULL DEFAULT '2000-01-01 00:00:00',\n\t\t\t ADD COLUMN hit_keyphrase_keyp_ID         INT UNSIGNED DEFAULT NULL AFTER hit_referer_dom_ID,\n\t\t\t ADD INDEX hit_remote_addr ( hit_remote_addr ),\n\t\t\t ADD INDEX hit_sess_ID        ( hit_sess_ID )";
        $DB->query($query);
        echo "OK.<br />\n";
        echo 'Upgrading sessions table... ';
        $DB->query("ALTER TABLE T_sessions\n\t\t\tALTER COLUMN sess_lastseen SET DEFAULT '2000-01-01 00:00:00',\n\t\t\tADD COLUMN sess_hitcount  INT(10) UNSIGNED NOT NULL DEFAULT 1 AFTER sess_key,\n\t\t\tADD KEY sess_user_ID (sess_user_ID)");
        echo "OK.<br />\n";
        echo 'Creating goal tracking table... ';
        $DB->query("CREATE TABLE T_track__goal(\n\t\t\t\t\t  goal_ID int(10) unsigned NOT NULL auto_increment,\n\t\t\t\t\t  goal_name varchar(50) default NULL,\n\t\t\t\t\t  goal_key varchar(32) default NULL,\n\t\t\t\t\t  goal_redir_url varchar(255) default NULL,\n\t\t\t\t\t  goal_default_value double default NULL,\n\t\t\t\t\t  PRIMARY KEY (goal_ID),\n\t\t\t\t\t  UNIQUE KEY goal_key (goal_key)\n          )");
        $DB->query("CREATE TABLE T_track__goalhit (\n\t\t\t\t\t  ghit_ID int(10) unsigned NOT NULL auto_increment,\n\t\t\t\t\t  ghit_goal_ID    int(10) unsigned NOT NULL,\n\t\t\t\t\t  ghit_hit_ID     int(10) unsigned NOT NULL,\n\t\t\t\t\t  ghit_params     TEXT default NULL,\n\t\t\t\t\t  PRIMARY KEY  (ghit_ID),\n\t\t\t\t\t  KEY ghit_goal_ID (ghit_goal_ID),\n\t\t\t\t\t  KEY ghit_hit_ID (ghit_hit_ID)\n         )");
        echo "OK.<br />\n";
        set_upgrade_checkpoint('9800');
    }
    if ($old_db_version < 9900) {
        // 3.0 part 1
        task_begin('Updating keyphrases in hitlog table... ');
        load_class('sessions/model/_hit.class.php', 'Hit');
        // New Hit object creation was added later, to fix upgrades from very old versions.
        // We create a new temp Hit object to be able to call the Hit::extract_params_from_referer() function which was static when this upgrade block was created.
        $tempHit = new Hit();
        $sql = 'SELECT SQL_NO_CACHE hit_ID, hit_referer
  		          FROM T_hitlog
   		         WHERE hit_referer_type = "search"
		           AND hit_keyphrase_keyp_ID IS NULL';
        // this line just in case we crashed in the middle, so we restart where we stopped
        $rows = $DB->get_results($sql, OBJECT, 'get all search hits');
        foreach ($rows as $row) {
            $params = $tempHit->extract_params_from_referer($row->hit_referer);
            if (empty($params['keyphrase'])) {
                continue;
            }
            $DB->begin();
            $sql = 'SELECT keyp_ID
			          FROM T_track__keyphrase
			         WHERE keyp_phrase = ' . $DB->quote($params['keyphrase']);
            $keyp_ID = $DB->get_var($sql, 0, 0, 'Get keyphrase ID');
            if (empty($keyp_ID)) {
                $sql = 'INSERT INTO T_track__keyphrase( keyp_phrase )
				        VALUES (' . $DB->quote($params['keyphrase']) . ')';
                $DB->query($sql, 'Add new keyphrase');
                $keyp_ID = $DB->insert_id;
            }
            $DB->query('UPDATE T_hitlog
			                SET hit_keyphrase_keyp_ID = ' . $keyp_ID . '
			              WHERE hit_ID = ' . $row->hit_ID, 'Update hit');
            $DB->commit();
            echo ". \n";
        }
        task_end();
        task_begin('Upgrading widgets table... ');
        $DB->query("ALTER TABLE T_widget\n\t\t\tCHANGE COLUMN wi_order wi_order INT(10) NOT NULL");
        task_end();
        task_begin('Upgrading Files table... ');
        $DB->query("ALTER TABLE T_files\n\t\t\t\t\t\t\t\tCHANGE COLUMN file_root_type file_root_type enum('absolute','user','collection','shared','skins') not null default 'absolute'");
        task_end();
        set_upgrade_checkpoint('9900');
    }
    if ($old_db_version < 9910) {
        // 3.0 part 2
        task_begin('Upgrading Blogs table... ');
        $DB->query("ALTER TABLE T_blogs CHANGE COLUMN blog_name blog_name varchar(255) NOT NULL default ''");
        task_end();
        task_begin('Adding new Post Types...');
        $DB->query("\n\t\t\tREPLACE INTO T_items__type( ptyp_ID, ptyp_name )\n\t\t\tVALUES ( 1500, 'Intro-Main' ),\n\t\t\t\t\t\t ( 1520, 'Intro-Cat' ),\n\t\t\t\t\t\t ( 1530, 'Intro-Tag' ),\n\t\t\t\t\t\t ( 1570, 'Intro-Sub' ),\n\t\t\t\t\t\t ( 1600, 'Intro-All' ) ");
        task_end();
        task_begin('Updating User table');
        $DB->query("ALTER TABLE T_users\n\t\t\t\t\t\t\t\t\tADD COLUMN user_avatar_file_ID int(10) unsigned default NULL AFTER user_validated");
        task_end();
        task_begin('Creating table for User field definitions');
        $DB->query("CREATE TABLE T_users__fielddefs (\n\t\t\t\tufdf_ID int(10) unsigned NOT NULL,\n\t\t\t\tufdf_type char(8) NOT NULL,\n\t\t\t\tufdf_name varchar(255) collate latin1_general_ci NOT NULL,\n\t\t\t\tPRIMARY KEY  (ufdf_ID)\n\t\t\t)");
        task_end();
        task_begin('Creating default field definitions...');
        $DB->query("\n\t    INSERT INTO T_users__fielddefs (ufdf_ID, ufdf_type, ufdf_name)\n\t\t\t VALUES ( 10000, 'email',    'MSN/Live IM'),\n\t\t\t\t\t\t\t( 10100, 'word',     'Yahoo IM'),\n\t\t\t\t\t\t\t( 10200, 'word',     'AOL AIM'),\n\t\t\t\t\t\t\t( 10300, 'number',   'ICQ ID'),\n\t\t\t\t\t\t\t( 40000, 'phone',    'Skype'),\n\t\t\t\t\t\t\t( 50000, 'phone',    'Main phone'),\n\t\t\t\t\t\t\t( 50100, 'phone',    'Cell phone'),\n\t\t\t\t\t\t\t( 50200, 'phone',    'Office phone'),\n\t\t\t\t\t\t\t( 50300, 'phone',    'Home phone'),\n\t\t\t\t\t\t\t( 60000, 'phone',    'Office FAX'),\n\t\t\t\t\t\t\t( 60100, 'phone',    'Home FAX'),\n\t\t\t\t\t\t\t(100000, 'url',      'Website'),\n\t\t\t\t\t\t\t(100100, 'url',      'Blog'),\n\t\t\t\t\t\t\t(110000, 'url',      'Linkedin'),\n\t\t\t\t\t\t\t(120000, 'url',      'Twitter'),\n\t\t\t\t\t\t\t(130100, 'url',      'Facebook'),\n\t\t\t\t\t\t\t(130200, 'url',      'Myspace'),\n\t\t\t\t\t\t\t(140000, 'url',      'Flickr'),\n\t\t\t\t\t\t\t(150000, 'url',      'YouTube'),\n\t\t\t\t\t\t\t(160000, 'url',      'Digg'),\n\t\t\t\t\t\t\t(160100, 'url',      'StumbleUpon'),\n\t\t\t\t\t\t\t(200000, 'text',     'Role'),\n\t\t\t\t\t\t\t(200100, 'text',     'Company/Org.'),\n\t\t\t\t\t\t\t(200200, 'text',     'Division'),\n\t\t\t\t\t\t\t(211000, 'text',     'VAT ID'),\n\t\t\t\t\t\t\t(300000, 'text',     'Main address'),\n\t\t\t\t\t\t\t(300300, 'text',     'Home address');");
        task_end();
        task_begin('Creating table for User fields...');
        $DB->query("CREATE TABLE {$tableprefix}users_fields (\n\t\t\t\tuf_ID      int(10) unsigned NOT NULL auto_increment,\n\t\t\t  uf_user_ID int(10) unsigned NOT NULL,\n\t\t\t  uf_ufdf_ID int(10) unsigned NOT NULL,\n\t\t\t  uf_varchar varchar(255) NOT NULL,\n\t\t\t  PRIMARY KEY (uf_ID)\n\t\t\t)");
        task_end();
        set_upgrade_checkpoint('9910');
    }
    if ($old_db_version < 9920) {
        // 3.1
        task_begin('Upgrading Posts table... ');
        // This is for old posts that may have a post type of NULL which should never happen. ptyp 1 is for regular posts
        $DB->query("UPDATE T_items__item\n\t\t\t\t\t\t\t\t\t\tSET post_ptyp_ID = 1\n\t\t\t\t\t\t\t\t\tWHERE post_ptyp_ID IS NULL");
        $DB->query("ALTER TABLE T_items__item\n\t\t\t\t\t\t\tCHANGE COLUMN post_ptyp_ID post_ptyp_ID int(10) unsigned NOT NULL DEFAULT 1");
        task_end();
        task_begin('Upgrading Categories table... ');
        $DB->query("ALTER TABLE T_categories\n\t\t\tCHANGE COLUMN cat_name cat_name varchar(255) NOT NULL,\n\t\t\tCHANGE COLUMN cat_description cat_description varchar(255) NULL DEFAULT NULL");
        db_add_col('T_categories', 'cat_order', 'int(11) NULL DEFAULT NULL AFTER cat_description');
        db_add_index('T_categories', 'cat_order', 'cat_order');
        $DB->query("UPDATE T_categories\n\t\t\t\t\tSET cat_order = cat_ID");
        task_end();
        task_begin('Upgrading widgets table... ');
        db_add_col('T_widget', 'wi_enabled', 'tinyint(1) NOT NULL DEFAULT 1 AFTER wi_order');
        task_end();
    }
    if ($old_db_version < 9930) {
        // 3.1 continued
        task_begin('Updating Post Types...');
        $DB->query("\n\t\t\tREPLACE INTO T_items__type ( ptyp_ID, ptyp_name )\n\t\t\tVALUES ( 3000, 'Sidebar link' )");
        echo "OK.<br />\n";
        task_end();
        task_begin('Updating items table...');
        $DB->query("ALTER TABLE T_items__item ENGINE=innodb");
        // fp> hum... this originally was a test :)
        task_end();
        task_begin('Creating versions table...');
        $DB->query("CREATE TABLE T_items__version (\n\t            iver_itm_ID        INT UNSIGNED NOT NULL ,\n\t            iver_edit_user_ID  INT UNSIGNED NOT NULL ,\n\t            iver_edit_datetime DATETIME NOT NULL ,\n\t            iver_status        ENUM('published','deprecated','protected','private','draft','redirected') NULL ,\n\t            iver_title         TEXT NULL ,\n\t            iver_content       MEDIUMTEXT NULL ,\n\t            INDEX iver_itm_ID ( iver_itm_ID )\n\t            ) ENGINE = innodb");
        task_end();
        task_begin('Updating group permissions...');
        $DB->query("UPDATE T_groups\n\t\t\t\t\t\t\t\t\t\tSET grp_perm_xhtml_css_tweaks = 1\n\t\t\t\t\t\t\t\t\tWHERE grp_ID <= 3");
        task_end();
        set_upgrade_checkpoint('9930');
    }
    if ($old_db_version < 9940) {
        // 3.2
        task_begin('Updating hitlog table...');
        $DB->query("ALTER TABLE T_hitlog ADD COLUMN hit_serprank INT UNSIGNED DEFAULT NULL AFTER hit_keyphrase_keyp_ID");
        task_end();
        task_begin('Updating versions table...');
        $DB->query("ALTER TABLE T_items__version\n\t\t\t\t\t\t\t\tCHANGE COLUMN iver_edit_user_ID iver_edit_user_ID  INT UNSIGNED NULL");
        task_end();
    }
    if ($old_db_version < 9950) {
        // 3.3
        task_begin('Altering Blogs table... ');
        $DB->query("ALTER TABLE T_blogs CHANGE COLUMN blog_shortname blog_shortname varchar(255) default ''");
        task_end();
        task_begin('Altering default dates... ');
        $DB->query("ALTER TABLE T_links\n      ALTER COLUMN link_datecreated SET DEFAULT '2000-01-01 00:00:00',\n      ALTER COLUMN link_datemodified SET DEFAULT '2000-01-01 00:00:00'");
        $DB->query("ALTER TABLE T_cron__task\n      ALTER COLUMN ctsk_start_datetime SET DEFAULT '2000-01-01 00:00:00'");
        $DB->query("ALTER TABLE T_cron__log\n      ALTER COLUMN clog_realstart_datetime SET DEFAULT '2000-01-01 00:00:00'");
        task_end();
        task_begin('Altering Items table... ');
        $DB->query("ALTER TABLE T_items__item\n\t\t\tADD COLUMN post_metadesc VARCHAR(255) NULL DEFAULT NULL AFTER post_titletag,\n\t\t\tADD COLUMN post_metakeywords VARCHAR(255) NULL DEFAULT NULL AFTER post_metadesc,\n\t\t\tADD COLUMN post_editor_code VARCHAR(32) NULL COMMENT 'Plugin code of the editor used to edit this post' AFTER post_varchar3");
        task_end();
        task_begin('Forcing AutoP posts to html editor...');
        $DB->query('UPDATE T_items__item
											SET post_editor_code = "html"
										WHERE post_renderers = "default"
											 OR post_renderers LIKE "%b2WPAutP%"');
        task_end();
        set_upgrade_checkpoint('9950');
    }
    if ($old_db_version < 9960) {
        // 3.3
        echo "Renaming tables...";
        $DB->save_error_state();
        $DB->halt_on_error = false;
        $DB->show_errors = false;
        $DB->query("ALTER TABLE {$tableprefix}users_fields RENAME TO T_users__fields");
        $DB->restore_error_state();
        echo "OK.<br />\n";
        // fp> The following is more tricky to do with CHARACTER SET. During upgrade, we don't know what the admin actually wants.
        task_begin('Making sure all tables use desired storage ENGINE as specified in the b2evo schema...');
        foreach ($schema_queries as $table_name => $table_def) {
            if ($DB->query('SHOW TABLES LIKE \'' . $table_name . '\'') && preg_match('/\\sENGINE\\s*=\\s*([a-z]+)/is', $table_def[1], $matches)) {
                // If the table exists and has an ENGINE definition:
                echo $table_name . ':' . $matches[1] . '<br />';
                $DB->query("ALTER TABLE {$table_name} ENGINE = " . $matches[1]);
            }
        }
        task_end();
        set_upgrade_checkpoint('9960');
    }
    if ($old_db_version < 9970) {
        // 4.0 part 1
        // For create_default_currencies() and create_default_countries():
        require_once dirname(__FILE__) . '/_functions_create.php';
        task_begin('Creating table for default currencies... ');
        $DB->query('CREATE TABLE ' . $tableprefix . 'currency (
				curr_ID int(10) unsigned NOT NULL auto_increment,
				curr_code char(3) NOT NULL,
				curr_shortcut varchar(30) NOT NULL,
				curr_name varchar(40) NOT NULL,
				PRIMARY KEY curr_ID (curr_ID),
				UNIQUE curr_code (curr_code)
			) ENGINE = innodb');
        task_end();
        create_default_currencies($tableprefix . 'currency');
        task_begin('Creating table for default countries... ');
        $DB->query('CREATE TABLE ' . $tableprefix . 'country (
				ctry_ID int(10) unsigned NOT NULL auto_increment,
				ctry_code char(2) NOT NULL,
				ctry_name varchar(40) NOT NULL,
				ctry_curr_ID int(10) unsigned,
				PRIMARY KEY ctry_ID (ctry_ID),
				UNIQUE ctry_code (ctry_code)
			) ENGINE = innodb');
        task_end();
        create_default_countries($tableprefix . 'country', false);
        task_begin('Upgrading user permissions table... ');
        $DB->query("ALTER TABLE T_coll_user_perms\n\t\t\tADD COLUMN bloguser_perm_page\t\ttinyint NOT NULL default 0 AFTER bloguser_perm_media_change,\n\t\t\tADD COLUMN bloguser_perm_intro\t\ttinyint NOT NULL default 0 AFTER bloguser_perm_page,\n\t\t\tADD COLUMN bloguser_perm_podcast\ttinyint NOT NULL default 0 AFTER bloguser_perm_intro,\n\t\t\tADD COLUMN bloguser_perm_sidebar\ttinyint NOT NULL default 0 AFTER bloguser_perm_podcast");
        task_end();
        task_begin('Upgrading group permissions table... ');
        $DB->query("ALTER TABLE T_coll_group_perms\n\t\t\tADD COLUMN bloggroup_perm_page\t\ttinyint NOT NULL default 0 AFTER bloggroup_perm_media_change,\n\t\t\tADD COLUMN bloggroup_perm_intro\t\ttinyint NOT NULL default 0 AFTER bloggroup_perm_page,\n\t\t\tADD COLUMN bloggroup_perm_podcast\ttinyint NOT NULL default 0 AFTER bloggroup_perm_intro,\n\t\t\tADD COLUMN bloggroup_perm_sidebar\ttinyint NOT NULL default 0 AFTER bloggroup_perm_podcast");
        task_end();
        task_begin('Upgrading users table... ');
        $DB->query("ALTER TABLE T_users\n\t\t\tADD COLUMN user_ctry_ID int(10) unsigned NULL AFTER user_avatar_file_ID");
        task_end();
        // Creating tables for messaging module
        task_begin('Creating table for message threads... ');
        $DB->query("CREATE TABLE T_messaging__thread (\n\t\t\tthrd_ID int(10) unsigned NOT NULL auto_increment,\n\t\t\tthrd_title varchar(255) NOT NULL,\n\t\t\tthrd_datemodified datetime NOT NULL,\n\t\t\tPRIMARY KEY thrd_ID (thrd_ID)\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Creating table for messagee... ');
        $DB->query("CREATE TABLE T_messaging__message (\n\t\t\tmsg_ID int(10) unsigned NOT NULL auto_increment,\n\t\t\tmsg_author_user_ID int(10) unsigned NOT NULL,\n\t\t\tmsg_datetime datetime NOT NULL,\n\t\t\tmsg_thread_ID int(10) unsigned NOT NULL,\n\t\t\tmsg_text text NULL,\n\t\t\tPRIMARY KEY msg_ID (msg_ID)\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Creating table for message thread statuses... ');
        $DB->query("CREATE TABLE T_messaging__threadstatus (\n\t\t\ttsta_thread_ID int(10) unsigned NOT NULL,\n\t\t\ttsta_user_ID int(10) unsigned NOT NULL,\n\t\t\ttsta_first_unread_msg_ID int(10) unsigned NULL,\n\t\t\tINDEX(tsta_user_ID)\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Creating table for messaging contacts... ');
        $DB->query("CREATE TABLE T_messaging__contact (\n\t\t\tmct_from_user_ID int(10) unsigned NOT NULL,\n\t\t\tmct_to_user_ID int(10) unsigned NOT NULL,\n\t\t\tmct_blocked tinyint(1) default 0,\n\t\t\tmct_last_contact_datetime datetime NOT NULL,\n\t\t\tPRIMARY KEY mct_PK (mct_from_user_ID, mct_to_user_ID)\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Upgrading skins table... ');
        $DB->query("ALTER TABLE T_skins__skin\n\t\t\t\t\t\tMODIFY skin_type enum('normal','feed','sitemap') NOT NULL default 'normal'");
        task_end();
        task_begin('Setting skin type of sitemap skin to "sitemap"... ');
        $DB->query("UPDATE T_skins__skin\n\t\t\t\t\t\tSET skin_type = 'sitemap'\n\t\t\t\t\t\tWHERE skin_folder = '_sitemap'");
        task_end();
        // Creating table for pluggable permissions
        // This table gets created during upgrade to v0.8.9 at checkpoint 8050
        task_begin('Creating table for Group Settings... ');
        $DB->query("CREATE TABLE IF NOT EXISTS T_groups__groupsettings (\n\t\t\tgset_grp_ID INT(11) UNSIGNED NOT NULL,\n\t\t\tgset_name VARCHAR(30) NOT NULL,\n\t\t\tgset_value VARCHAR(255) NULL,\n\t\t\tPRIMARY KEY (gset_grp_ID, gset_name)\n\t\t) ENGINE = innodb");
        task_end();
        // Rename T_usersettings table to T_users__usersettings
        task_begin('Rename T_usersettings table to T_users__usersettings... ');
        $DB->query('ALTER TABLE ' . $tableprefix . 'usersettings RENAME TO T_users__usersettings');
        task_end();
        set_upgrade_checkpoint('9970');
    }
    if ($old_db_version < 9980) {
        // 4.0 part 2
        task_begin('Upgrading posts... ');
        $DB->query('
			UPDATE T_items__item
			   SET post_datestart = FROM_UNIXTIME( FLOOR(UNIX_TIMESTAMP(post_datestart)/60)*60 )
			 WHERE post_datestart > NOW()');
        db_add_col('T_items__item', 'post_excerpt_autogenerated', 'TINYINT NULL DEFAULT NULL AFTER post_excerpt');
        db_add_col('T_items__item', 'post_dateset', 'tinyint(1) NOT NULL DEFAULT 1 AFTER post_assigned_user_ID');
        task_end();
        task_begin('Upgrading countries... ');
        db_add_col($tableprefix . 'country', 'ctry_enabled', 'tinyint(1) NOT NULL DEFAULT 1 AFTER ctry_curr_ID');
        task_end();
        task_begin('Upgrading links... ');
        // Add link_position. Temporary allow NULL, set compatibility default, then do not allow NULL.
        // TODO: dh> actually, using "teaser" for the first link and "aftermore" for the rest would make more sense (and "aftermore" should get displayed with "no-more" posts anyway).
        //           Opinions? Could be heavy to transform this though..
        // fp> no, don't change past posts unexpectedly.
        db_add_col('T_links', 'link_position', "varchar(10) NULL AFTER link_title");
        $DB->query("UPDATE T_links SET link_position = 'teaser' WHERE link_position IS NULL");
        db_add_col('T_links', 'link_position', "varchar(10) NOT NULL AFTER link_title");
        // change to NOT NULL
        // Add link_order. Temporary allow NULL, use order from ID, then do not allow NULL and add UNIQUE index.
        db_add_col('T_links', 'link_order', 'int(11) unsigned NULL AFTER link_position');
        $DB->query("UPDATE T_links SET link_order = link_ID WHERE link_order IS NULL");
        db_add_col('T_links', 'link_order', 'int(11) unsigned NOT NULL AFTER link_position');
        // change to NOT NULL
        db_add_index('T_links', 'link_itm_ID_order', 'link_itm_ID, link_order', 'UNIQUE');
        task_end();
        task_begin('Upgrading sessions... ');
        $DB->query("ALTER TABLE T_sessions CHANGE COLUMN sess_ipaddress sess_ipaddress VARCHAR(39) NOT NULL DEFAULT ''");
        task_end();
        set_upgrade_checkpoint('9980');
    }
    if ($old_db_version < 9990) {
        // 4.0 part 3
        task_begin('Upgrading hitlog... ');
        db_add_col('T_hitlog', 'hit_agent_type', "ENUM('rss','robot','browser','unknown') DEFAULT 'unknown' NOT NULL AFTER hit_remote_addr");
        if (db_col_exists('T_hitlog', 'hit_agnt_ID')) {
            $DB->query('UPDATE T_hitlog, ' . $tableprefix . 'useragents
			                SET hit_agent_type = agnt_type
			              WHERE hit_agnt_ID = agnt_ID
			                AND agnt_type <> "unknown"');
            // We already have the unknown as default
            db_drop_col('T_hitlog', 'hit_agnt_ID');
        }
        $DB->query('DROP TABLE IF EXISTS ' . $tableprefix . 'useragents');
        task_end();
        set_upgrade_checkpoint('9990');
    }
    if ($old_db_version < 10000) {
        // 4.0 part 4
        // Integrate comment_secret
        task_begin('Extending Comment table... ');
        db_add_col('T_comments', 'comment_secret', 'varchar(32) NULL default NULL');
        task_end();
        // Create T_slug table and, Insert all slugs from T_items
        task_begin('Create Slugs table... ');
        $DB->query('CREATE TABLE IF NOT EXISTS T_slug (
						slug_ID int(10) unsigned NOT NULL auto_increment,
						slug_title varchar(255) NOT NULL COLLATE ascii_bin,
						slug_type char(6) NOT NULL DEFAULT "item",
						slug_itm_ID int(11) unsigned,
						PRIMARY KEY slug_ID (slug_ID),
						UNIQUE	slug_title (slug_title)
					) ENGINE = innodb');
        task_end();
        task_begin('Making sure all posts have a slug...');
        // Get posts with empty urltitle:
        $sql = 'SELECT post_ID, post_title
				      FROM T_items__item
				     WHERE post_urltitle IS NULL OR post_urltitle = ""';
        $rows = $DB->get_results($sql, OBJECT, 'Get posts with empty urltitle');
        // Create URL titles when non existent:
        foreach ($rows as $row) {
            // TODO: dh> pass locale (useful for transliteration).
            $DB->query('UPDATE T_items__item
				              SET post_urltitle = "' . urltitle_validate('', $row->post_title, 0) . '"
		                WHERE post_ID = ' . $row->post_ID, 'Set posts urltitle');
        }
        task_end();
        task_begin('Populating Slugs table... ');
        $DB->query('REPLACE INTO T_slug( slug_title, slug_type, slug_itm_ID)
		              SELECT post_urltitle, "item", post_ID
							      FROM T_items__item');
        task_end();
        task_begin('Add canonical and tiny slug IDs to post table...');
        // modify post_urltitle column -> Not allow NULL value
        db_add_col('T_items__item', 'post_urltitle', 'VARCHAR(210) NOT NULL');
        db_add_col('T_items__item', 'post_canonical_slug_ID', 'int(10) unsigned NULL default NULL after post_urltitle');
        db_add_col('T_items__item', 'post_tiny_slug_ID', 'int(10) unsigned NULL default NULL after post_canonical_slug_ID');
        task_end();
        task_begin('Upgrading posts...');
        $DB->query('UPDATE T_items__item, T_slug
			              SET post_canonical_slug_ID = slug_ID
			            WHERE CONVERT( post_urltitle USING ASCII ) COLLATE ascii_bin = slug_title');
        task_end();
        task_begin('Adding "help" slug...');
        if (db_key_exists('T_slug', 'slug_title', '"help"')) {
            echo '<strong>Warning: "help" slug already exists!</strong><br /> ';
        } else {
            $DB->query('INSERT INTO T_slug( slug_title, slug_type )
			             VALUES( "help", "help" )', 'Add "help" slug');
            task_end();
        }
        // fp> Next time we should use pluggable permissions instead.
        task_begin('Updgrading groups: Giving Administrators Group edit perms on slugs...');
        db_add_col('T_groups', 'grp_perm_slugs', "enum('none','view','edit') NOT NULL default 'none'");
        $DB->query('UPDATE T_groups
		             SET grp_perm_slugs = "edit"
		             WHERE grp_ID = 1');
        task_end();
        task_begin('Upgrading settings table... ');
        $DB->query('UPDATE T_settings
		                SET set_value = 1
		              WHERE set_name = "fm_enable_roots_user"
		                    AND set_value = 0');
        task_end();
        // New perms for comment moderation depending on status:
        task_begin('Upgrading Blog-User permissions...');
        db_add_col('T_coll_user_perms', 'bloguser_perm_draft_cmts', 'tinyint NOT NULL default 0 AFTER bloguser_perm_comments');
        db_add_col('T_coll_user_perms', 'bloguser_perm_publ_cmts', 'tinyint NOT NULL default 0 AFTER bloguser_perm_comments');
        db_add_col('T_coll_user_perms', 'bloguser_perm_depr_cmts', 'tinyint NOT NULL default 0 AFTER bloguser_perm_comments');
        if (db_col_exists('T_coll_user_perms', 'bloguser_perm_comments')) {
            // if user had perm_comments he now gets all 3 new perms also:
            $DB->query('UPDATE T_coll_user_perms
						SET bloguser_perm_draft_cmts = bloguser_perm_comments,
							bloguser_perm_publ_cmts = bloguser_perm_comments,
							bloguser_perm_depr_cmts = bloguser_perm_comments');
            db_drop_col('T_coll_user_perms', 'bloguser_perm_comments');
        }
        task_end();
        task_begin('Upgrading Blog-Group permissions...');
        db_add_col('T_coll_group_perms', 'bloggroup_perm_draft_cmts', 'tinyint NOT NULL default 0 AFTER bloggroup_perm_comments');
        db_add_col('T_coll_group_perms', 'bloggroup_perm_publ_cmts', 'tinyint NOT NULL default 0 AFTER bloggroup_perm_comments');
        db_add_col('T_coll_group_perms', 'bloggroup_perm_depr_cmts', 'tinyint NOT NULL default 0 AFTER bloggroup_perm_comments');
        if (db_col_exists('T_coll_group_perms', 'bloggroup_perm_comments')) {
            // if group had perm_comments he now gets all 3 new perms also:
            $DB->query('UPDATE T_coll_group_perms
						SET bloggroup_perm_draft_cmts = bloggroup_perm_comments,
							bloggroup_perm_publ_cmts = bloggroup_perm_comments,
							bloggroup_perm_depr_cmts = bloggroup_perm_comments');
            db_drop_col('T_coll_group_perms', 'bloggroup_perm_comments');
        }
        task_end();
        task_begin('Upgrading messaging permissions...');
        $DB->query('ALTER TABLE T_users ALTER COLUMN user_allow_msgform SET DEFAULT "2"');
        $DB->query('UPDATE T_users
					SET user_allow_msgform = 3
					WHERE user_allow_msgform = 1');
        task_end();
        task_begin('Upgrading currency table...');
        $DB->query('ALTER TABLE ' . $tableprefix . 'currency ADD COLUMN curr_enabled tinyint(1) NOT NULL DEFAULT 1 AFTER curr_name');
        task_end();
        task_begin('Upgrading default blog access type for new blogs...');
        $DB->query('ALTER TABLE T_blogs ALTER COLUMN blog_access_type SET DEFAULT "extrapath"');
        task_end();
        task_begin('Upgrading tags table...');
        $DB->query('ALTER TABLE T_items__tag CHANGE COLUMN tag_name tag_name varbinary(50) not null');
        task_end();
        // fp> I don't understand why we need to carry this out "again" but I observed the installer barking on
        // this setting missing when upgrading from older 2.x versions. I figured it would be no big deal to do it twice...
        task_begin('Makin sure usersettings table is InnoDB...');
        $DB->query('ALTER TABLE T_users__usersettings ENGINE=innodb');
        task_end();
        set_upgrade_checkpoint('10000');
    }
    if ($old_db_version < 10100) {
        // 4.1
        task_begin('Convert group permissions to pluggable permissions...');
        // asimo>This delete query needs just in case if this version of b2evo was used, before upgrade process call
        $DB->query('DELETE FROM T_groups__groupsettings
						WHERE gset_name = "perm_files" OR gset_name = "perm_options" OR gset_name = "perm_templates"');
        // Get current permission values from groups table
        $sql = 'SELECT grp_ID, grp_perm_spamblacklist, grp_perm_slugs, grp_perm_files, grp_perm_options, grp_perm_templates
				      FROM T_groups';
        $rows = $DB->get_results($sql, OBJECT, 'Get groups converted permissions');
        // Insert values into groupsettings table
        foreach ($rows as $row) {
            // "IGNORE" is needed if we already created T_groups__groupsettings during upgrade to v0.8.9 at checkpoint 8050
            $DB->query('INSERT IGNORE INTO T_groups__groupsettings( gset_grp_ID, gset_name, gset_value )
							VALUES( ' . $row->grp_ID . ', "perm_spamblacklist", "' . $row->grp_perm_spamblacklist . '" ),
								( ' . $row->grp_ID . ', "perm_slugs", "' . $row->grp_perm_slugs . '" ),
								( ' . $row->grp_ID . ', "perm_files", "' . $row->grp_perm_files . '" ),
								( ' . $row->grp_ID . ', "perm_options", "' . $row->grp_perm_options . '" ),
								( ' . $row->grp_ID . ', "perm_templates", "' . $row->grp_perm_templates . '" )');
        }
        // Drop all converted permissin colums from groups table
        db_drop_col('T_groups', 'grp_perm_spamblacklist');
        db_drop_col('T_groups', 'grp_perm_slugs');
        db_drop_col('T_groups', 'grp_perm_files');
        db_drop_col('T_groups', 'grp_perm_options');
        db_drop_col('T_groups', 'grp_perm_templates');
        task_end();
        task_begin('Upgrading users table, adding user gender...');
        db_add_col('T_users', 'user_gender', 'char(1) NULL DEFAULT NULL AFTER user_showonline');
        task_end();
        task_begin('Upgrading edit timpestamp blog-user permission...');
        db_add_col('T_coll_user_perms', 'bloguser_perm_edit_ts', 'tinyint NOT NULL default 0 AFTER bloguser_perm_delpost');
        $DB->query('UPDATE T_coll_user_perms, T_users
							SET bloguser_perm_edit_ts = 1
							WHERE bloguser_user_ID = user_ID  AND user_level > 4');
        task_end();
        task_begin('Upgrading edit timpestamp blog-group permission...');
        db_add_col('T_coll_group_perms', 'bloggroup_perm_edit_ts', 'tinyint NOT NULL default 0 AFTER bloggroup_perm_delpost');
        $DB->query('UPDATE T_coll_group_perms
							SET bloggroup_perm_edit_ts = 1
							WHERE bloggroup_group_ID = 1');
        task_end();
        task_begin('Upgrading comments table, add trash status...');
        $DB->query("ALTER TABLE T_comments MODIFY COLUMN comment_status ENUM('published','deprecated','draft', 'trash') DEFAULT 'published' NOT NULL");
        task_end();
        task_begin('Upgrading groups admin access permission...');
        $sql = 'SELECT grp_ID, grp_perm_admin
					FROM T_groups';
        $rows = $DB->get_results($sql, OBJECT, 'Get groups admin perms');
        foreach ($rows as $row) {
            switch ($row->grp_perm_admin) {
                case 'visible':
                    $value = 'normal';
                    break;
                case 'hidden':
                    $value = 'restricted';
                    break;
                default:
                    $value = 'none';
            }
            // "IGNORE" is needed if we already created T_groups__groupsettings during upgrade to v0.8.9 at checkpoint 8050
            $DB->query('INSERT IGNORE INTO T_groups__groupsettings( gset_grp_ID, gset_name, gset_value )
							VALUES( ' . $row->grp_ID . ', "perm_admin", "' . $value . '" )');
        }
        db_drop_col('T_groups', 'grp_perm_admin');
        task_end();
        task_begin('Upgrading users table, add users source...');
        db_add_col('T_users', 'user_source', 'varchar(30) NULL');
        task_end();
        task_begin('Upgrading blogs table: more granularity for comment allowing...');
        $DB->query('INSERT INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
						SELECT blog_ID, "allow_comments", "never"
							FROM T_blogs
							WHERE blog_allowcomments = "never"');
        db_drop_col('T_blogs', 'blog_allowcomments');
        task_end();
        task_begin('Upgrading blogs table: allow_rating fields...');
        $DB->query('UPDATE T_coll_settings
						SET cset_value = "any"
						WHERE cset_value = "always" AND cset_name = "allow_rating"');
        task_end();
        task_begin('Upgrading links table, add link_cmt_ID...');
        $DB->query('ALTER TABLE T_links
						MODIFY COLUMN link_itm_ID int(11) unsigned NULL,
						MODIFY COLUMN link_creator_user_ID int(11) unsigned NULL,
						MODIFY COLUMN link_lastedit_user_ID int(11) unsigned NULL,
						ADD COLUMN link_cmt_ID int(11) unsigned NULL COMMENT "Used for linking files to comments (comment attachments)" AFTER link_itm_ID');
        $DB->query('ALTER TABLE T_links
						ADD INDEX link_cmt_ID ( link_cmt_ID )');
        task_end();
        task_begin('Upgrading filetypes table...');
        // get allowed filetype ids
        $sql = 'SELECT ftyp_ID
					FROM T_filetypes
					WHERE ftyp_allowed != 0';
        $allowed_ids = implode(',', $DB->get_col($sql, 0, 'Get allowed filetypes'));
        // update table column  -- this column is about who can edit the filetype: any user, registered users or only admins.
        $DB->query('ALTER TABLE T_filetypes
						MODIFY COLUMN ftyp_allowed enum("any","registered","admin") NOT NULL default "admin"');
        // update ftyp_allowed column content
        $DB->query('UPDATE T_filetypes
						SET ftyp_allowed = "registered"
						WHERE ftyp_ID IN (' . $allowed_ids . ')');
        $DB->query('UPDATE T_filetypes
						SET ftyp_allowed = "admin"
						WHERE ftyp_ID NOT IN (' . $allowed_ids . ')');
        $DB->query('UPDATE T_filetypes
						SET ftyp_allowed = "any"
						WHERE ftyp_extensions = "gif" OR ftyp_extensions = "png" OR ftyp_extensions LIKE "%jpg%"');
        // Add m4v file type if not exists
        if (!db_key_exists('T_filetypes', 'ftyp_extensions', '"m4v"')) {
            $DB->query('INSERT INTO T_filetypes (ftyp_extensions, ftyp_name, ftyp_mimetype, ftyp_icon, ftyp_viewtype, ftyp_allowed)
				             VALUES ("m4v", "MPEG video file", "video/x-m4v", "", "browser", "registered")', 'Add "m4v" file type');
        }
        task_end();
        // The AdSense plugin needs to store quite long strings of data...
        task_begin('Upgrading collection settings table, change cset_value type...');
        $DB->query('ALTER TABLE T_coll_settings
								 MODIFY COLUMN cset_name VARCHAR(50) NOT NULL,
								 MODIFY COLUMN cset_value VARCHAR(10000) NULL');
        task_end();
        set_upgrade_checkpoint('10100');
    }
    if ($old_db_version < 10200) {
        // 4.1b
        task_begin('Creating table for a specific blog post subscriptions...');
        $DB->query("CREATE TABLE T_items__subscriptions (\n\t\t\t\t\t\tisub_item_ID  int(11) unsigned NOT NULL,\n\t\t\t\t\t\tisub_user_ID  int(11) unsigned NOT NULL,\n\t\t\t\t\t\tisub_comments tinyint(1) NOT NULL default 0 COMMENT 'The user wants to receive notifications for new comments on this post',\n\t\t\t\t\t\tPRIMARY KEY (isub_item_ID, isub_user_ID )\n\t\t\t\t\t) ENGINE = innodb");
        task_end();
        task_begin('Upgrading comments table, add subscription fields...');
        db_add_col('T_comments', 'comment_notif_status', 'ENUM("noreq","todo","started","finished") NOT NULL DEFAULT "noreq" COMMENT "Have notifications been sent for this comment? How far are we in the process?" AFTER comment_secret');
        db_add_col('T_comments', 'comment_notif_ctsk_ID', 'INT(10) unsigned NULL DEFAULT NULL COMMENT "When notifications for this comment are sent through a scheduled job, what is the job ID?" AFTER comment_notif_status');
        task_end();
        task_begin('Upgrading users table...');
        db_add_col('T_users', 'user_notify_moderation', 'tinyint(1) NOT NULL default 0 COMMENT "Notify me by email whenever a comment is awaiting moderation on one of my blogs" AFTER user_notify');
        db_add_col('T_users', 'user_unsubscribe_key', 'varchar(32) NOT NULL default "" COMMENT "A specific key, it is used when a user wants to unsubscribe from a post comments without signing in" AFTER user_notify_moderation');
        // Set unsubscribe keys for existing users with no unsubscribe key
        $sql = 'SELECT user_ID
							FROM T_users
						 WHERE user_unsubscribe_key = ""';
        $rows = $DB->get_results($sql, OBJECT, 'Get users with no unsubscribe key');
        foreach ($rows as $row) {
            $DB->query('UPDATE T_users
							SET user_unsubscribe_key = "' . generate_random_key() . '"
							WHERE user_ID = ' . $row->user_ID);
        }
        task_end();
        task_begin('Upgrading settings table... ');
        // This query was removed later, to avoid performance issue because of the smart view counting
        /*$DB->query( 'INSERT INTO T_settings (set_name, set_value)
        		VALUES ( "smart_hit_count", 1 )' );*/
        $DB->query('ALTER TABLE T_coll_settings
									CHANGE COLUMN cset_value cset_value   VARCHAR( 10000 ) NULL COMMENT "The AdSense plugin wants to store very long snippets of HTML"');
        task_end();
        // The following two upgrade task were created subsequently to "Make sure DB schema is up to date".
        // Note: These queries don't modify the correct databases
        task_begin('Upgrading users table, no notification by default...');
        $DB->query('ALTER TABLE T_users ALTER COLUMN user_notify SET DEFAULT 0');
        task_end();
        task_begin('Upgrading items table...');
        $DB->query('ALTER TABLE T_items__item CHANGE COLUMN post_priority post_priority int(11) unsigned null COMMENT "Task priority in workflow"');
        task_end();
        set_upgrade_checkpoint('10200');
    }
    if ($old_db_version < 10300) {
        // 4.2
        task_begin('Upgrading user fields...');
        $DB->query('ALTER TABLE T_users__fielddefs
									ADD COLUMN ufdf_required enum("hidden","optional","recommended","require") NOT NULL default "optional"');
        $DB->query('UPDATE T_users__fielddefs
										SET ufdf_required = "recommended"
									WHERE ufdf_name in ("Website", "Twitter", "Facebook") ');
        $DB->query("REPLACE INTO T_users__fielddefs (ufdf_ID, ufdf_type, ufdf_name, ufdf_required)\n\t\t\t \t\t\t\t\t\tVALUES (400000, 'text', 'About me', 'recommended');");
        task_end();
        task_begin('Moving data to user fields...');
        $DB->query('INSERT INTO T_users__fields( uf_user_ID, uf_ufdf_ID, uf_varchar )
								 SELECT user_ID, 10300, user_icq
									 FROM T_users
								  WHERE user_icq IS NOT NULL AND TRIM(user_icq) <> ""');
        $DB->query('INSERT INTO T_users__fields( uf_user_ID, uf_ufdf_ID, uf_varchar )
								 SELECT user_ID, 10200, user_aim
									 FROM T_users
								  WHERE user_aim IS NOT NULL AND TRIM(user_aim) <> ""');
        $DB->query('INSERT INTO T_users__fields( uf_user_ID, uf_ufdf_ID, uf_varchar )
								 SELECT user_ID, 10000, user_msn
									 FROM T_users
								  WHERE user_msn IS NOT NULL AND TRIM(user_msn) <> ""');
        $DB->query('INSERT INTO T_users__fields( uf_user_ID, uf_ufdf_ID, uf_varchar )
								 SELECT user_ID, 10100, user_yim
									 FROM T_users
								  WHERE user_yim IS NOT NULL AND TRIM(user_yim) <> ""');
        task_end();
        task_begin('Dropping obsolete user columns...');
        $DB->query('ALTER TABLE T_users
									DROP COLUMN user_icq,
									DROP COLUMN user_aim,
									DROP COLUMN user_msn,
									DROP COLUMN user_yim');
        task_end();
        // ---
        task_begin('Adding new user columns...');
        $DB->query('ALTER TABLE T_users
									ADD COLUMN user_postcode varchar(12) NULL AFTER user_ID,
									ADD COLUMN user_age_min int unsigned NULL AFTER user_postcode,
									ADD COLUMN user_age_max int unsigned NULL AFTER user_age_min');
        task_end();
        task_begin('Upgrading item table for hide teaser...');
        $DB->query('ALTER TABLE T_items__item
						ADD COLUMN post_hideteaser tinyint(1) NOT NULL DEFAULT 0 AFTER post_featured');
        $DB->query('UPDATE T_items__item
										SET post_hideteaser = 1
									WHERE post_content LIKE "%<!--noteaser-->%"');
        task_end();
        task_begin('Creating table for a specific post settings...');
        $DB->query("CREATE TABLE T_items__item_settings (\n\t\t\t\t\t\tiset_item_ID  int(10) unsigned NOT NULL,\n\t\t\t\t\t\tiset_name     varchar( 50 ) NOT NULL,\n\t\t\t\t\t\tiset_value    varchar( 2000 ) NULL,\n\t\t\t\t\t\tPRIMARY KEY ( iset_item_ID, iset_name )\n\t\t\t\t\t) ENGINE = innodb");
        task_end();
        task_begin('Adding new column to comments...');
        $DB->query('ALTER TABLE T_comments
									ADD COLUMN comment_in_reply_to_cmt_ID INT(10) unsigned NULL AFTER comment_status');
        task_end();
        task_begin('Create table for internal searches...');
        $DB->query('CREATE TABLE T_logs__internal_searches (
						isrch_ID bigint(20) NOT NULL auto_increment,
						isrch_coll_ID bigint(20) NOT NULL,
						isrch_hit_ID bigint(20) NOT NULL,
						isrch_keywords varchar(255) NOT NULL,
						PRIMARY KEY (isrch_ID)
					) ENGINE = MyISAM');
        task_end();
        task_begin('Create table for comments votes...');
        $DB->query('CREATE TABLE T_comments__votes (
						cmvt_cmt_ID  int(10) unsigned NOT NULL,
						cmvt_user_ID int(10) unsigned NOT NULL,
						cmvt_helpful TINYINT(1) NULL DEFAULT NULL,
						cmvt_spam    TINYINT(1) NULL DEFAULT NULL,
						PRIMARY KEY (cmvt_cmt_ID, cmvt_user_ID),
						KEY cmvt_cmt_ID (cmvt_cmt_ID),
						KEY cmvt_user_ID (cmvt_user_ID)
					) ENGINE = innodb');
        task_end();
        task_begin('Adding new comments columns...');
        $DB->query('ALTER TABLE T_comments
									ADD comment_helpful_addvotes INT NOT NULL DEFAULT 0 AFTER comment_nofollow ,
									ADD comment_helpful_countvotes INT UNSIGNED NOT NULL DEFAULT 0 AFTER comment_helpful_addvotes ,
									ADD comment_spam_addvotes INT NOT NULL DEFAULT 0 AFTER comment_helpful_countvotes ,
									ADD comment_spam_countvotes INT UNSIGNED NOT NULL DEFAULT 0 AFTER comment_spam_addvotes ,
									CHANGE COLUMN comment_notif_ctsk_ID comment_notif_ctsk_ID      INT(10) unsigned NULL DEFAULT NULL COMMENT "When notifications for this comment are sent through a scheduled job, what is the job ID?"');
        task_end();
        task_begin('Adding new user permission for spam voting...');
        $DB->query('ALTER TABLE T_coll_user_perms
									ADD bloguser_perm_vote_spam_cmts tinyint NOT NULL default 0 AFTER bloguser_perm_edit_ts');
        task_end();
        task_begin('Adding new group permission for spam voting...');
        $DB->query('ALTER TABLE T_coll_group_perms
									ADD bloggroup_perm_vote_spam_cmts tinyint NOT NULL default 0 AFTER bloggroup_perm_edit_ts');
        task_end();
        task_begin('Upgrading countries table...');
        $DB->query('ALTER TABLE ' . $tableprefix . 'country ADD COLUMN ctry_preferred tinyint(1) NOT NULL DEFAULT 0 AFTER ctry_enabled');
        task_end();
        $DB->query('ALTER TABLE T_items__subscriptions CHANGE COLUMN isub_comments isub_comments   tinyint(1) NOT NULL DEFAULT 0 COMMENT "The user wants to receive notifications for new comments on this post"');
        set_upgrade_checkpoint('10300');
    }
    if ($old_db_version < 10400) {
        // 4.2 part 2
        task_begin('Updating "Post by Email" settings...');
        $DB->query('UPDATE T_settings SET set_name = "eblog_autobr" WHERE set_name = "AutoBR"');
        task_end();
        if ($DB->get_var('SELECT set_value FROM T_settings WHERE set_name = "eblog_enabled"')) {
            // eblog enabled, let's create a scheduled job for it
            task_begin('Creating "Post by Email" scheduled job...');
            $start_date = form_date(date2mysql($GLOBALS['localtimenow'] + 86400), '05:00:00');
            // start tomorrow
            $DB->query('
				INSERT INTO T_cron__task ( ctsk_start_datetime, ctsk_repeat_after, ctsk_name, ctsk_controller, ctsk_params )
				VALUES ( ' . $DB->quote($start_date) . ', 86400, ' . $DB->quote(T_('Create posts by email')) . ', ' . $DB->quote('cron/jobs/_post_by_email.job.php') . ', ' . $DB->quote('N;') . ' )');
            task_end();
        }
        task_begin('Upgrading hitlog table...');
        $DB->query('ALTER TABLE T_hitlog
								ADD COLUMN hit_disp        VARCHAR(30) DEFAULT NULL AFTER hit_uri,
								ADD COLUMN hit_ctrl        VARCHAR(30) DEFAULT NULL AFTER hit_disp,
								ADD COLUMN hit_response_code     INT DEFAULT NULL AFTER hit_agent_type ');
        task_end();
        task_begin('Upgrading file types...');
        // Update ftyp_icon column
        // Previous versions used a image file name for this field,
        // but from now we should use a icon name from the file /conf/_icons.php
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_image"
						WHERE ftyp_extensions IN ( "gif", "png", "jpg jpeg" )');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_document"
						WHERE ftyp_extensions = "txt"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_www"
						WHERE ftyp_extensions = "htm html"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_pdf"
						WHERE ftyp_extensions = "pdf"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_doc"
						WHERE ftyp_extensions = "doc"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_xls"
						WHERE ftyp_extensions = "xls"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_ppt"
						WHERE ftyp_extensions = "ppt"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_pps"
						WHERE ftyp_extensions = "pps"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_zip"
						WHERE ftyp_extensions = "zip"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_php"
						WHERE ftyp_extensions = "php php3 php4 php5 php6"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = ""
						WHERE ftyp_extensions = "css"');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_sound"
						WHERE ftyp_extensions IN ( "mp3", "m4a" )');
        $DB->query('UPDATE T_filetypes
						SET ftyp_icon = "file_video"
						WHERE ftyp_extensions IN ( "mp4", "mov", "m4v" )');
        task_end();
        set_upgrade_checkpoint('10400');
    }
    if ($old_db_version < 10500) {
        //  part 3
        task_begin('Upgrading hitlog table...');
        $DB->query("ALTER TABLE T_hitlog\n\t\t\t\t\t\t\t\tCHANGE COLUMN hit_referer_type  hit_referer_type ENUM(  'search',  'special',  'spam',  'referer',  'direct',  'self',  'admin', 'blacklist' ) NOT NULL,\n\t\t\t\t\t\t\t\tADD COLUMN hit_type ENUM('standard','rss','admin','ajax', 'service') DEFAULT 'standard' NOT NULL AFTER hit_ctrl,\n\t\t\t\t\t\t\t\tADD COLUMN hit_action VARCHAR(30) DEFAULT NULL AFTER hit_ctrl");
        $DB->query('UPDATE T_hitlog SET hit_referer_type = "special" WHERE hit_referer_type = "blacklist"');
        $DB->query('UPDATE T_hitlog SET hit_type = "admin", hit_referer_type = "direct"  WHERE hit_referer_type = "admin"');
        $DB->query("ALTER TABLE T_hitlog\n\t\t\t\t\t\t\t\tCHANGE COLUMN hit_referer_type  hit_referer_type ENUM(  'search',  'special',  'spam',  'referer',  'direct',  'self' ) NOT NULL");
        task_end();
        task_begin('Creating table for Groups of user field definitions...');
        $DB->query('CREATE TABLE T_users__fieldgroups (
				ufgp_ID int(10) unsigned NOT NULL auto_increment,
				ufgp_name varchar(255) NOT NULL,
				ufgp_order int(11) NOT NULL,
				PRIMARY KEY (ufgp_ID)
			) ENGINE = innodb');
        $DB->query('INSERT INTO T_users__fieldgroups ( ufgp_name, ufgp_order )
				VALUES ( "Instant Messaging", "1" ),
							 ( "Phone", "2" ),
							 ( "Web", "3" ),
							 ( "Organization", "4" ),
							 ( "Address", "5" ),
							 ( "Other", "6" ) ');
        task_end();
        task_begin('Upgrading user field definitions...');
        // Add new fields:
        // 		"ufdf_options" to save a values of the Option list
        // 		"ufdf_duplicated" to add a several instances
        // 		"ufdf_ufgp_ID" - Group ID
        // 		"ufdf_order" - Order number
        // 		"ufdf_suggest" - Suggest values
        $DB->query('ALTER TABLE T_users__fielddefs
						ADD ufdf_options    TEXT NOT NULL AFTER ufdf_name,
						ADD ufdf_duplicated enum("forbidden","allowed","list") NOT NULL default "allowed",
						ADD ufdf_ufgp_ID    int(10) unsigned NOT NULL AFTER ufdf_ID,
						ADD ufdf_order      int(11) NOT NULL,
						ADD ufdf_suggest    tinyint(1) NOT NULL DEFAULT 0,
						CHANGE ufdf_ID ufdf_ID int(10) UNSIGNED NOT NULL AUTO_INCREMENT');
        // Set default values of the field "ufdf_duplicated"
        $DB->query('UPDATE T_users__fielddefs
						SET ufdf_duplicated = "allowed"
						WHERE ufdf_ID IN ( 10000, 10100, 10200, 10300, 50100, 50200, 100000, 100100 )');
        // Group fields by default
        $DB->query('UPDATE T_users__fielddefs
						SET ufdf_ufgp_ID = "1"
						WHERE ufdf_ID <= 40000 ');
        $DB->query('UPDATE T_users__fielddefs
						SET ufdf_ufgp_ID = "2"
						WHERE ufdf_ID > 40000 AND ufdf_ID <= 60100');
        $DB->query('UPDATE T_users__fielddefs
						SET ufdf_ufgp_ID = "3"
						WHERE ufdf_ID > 60100 AND ufdf_ID <= 160100');
        $DB->query('UPDATE T_users__fielddefs
						SET ufdf_ufgp_ID = "4"
						WHERE ufdf_ID > 160100 AND ufdf_ID <= 211000');
        $DB->query('UPDATE T_users__fielddefs
						SET ufdf_ufgp_ID = "5"
						WHERE ufdf_ID > 211000 AND ufdf_ID <= 300300');
        $DB->query('UPDATE T_users__fielddefs
						SET ufdf_ufgp_ID = "6"
						WHERE ufdf_ID > 300300');
        // Set order field
        $userfields = $DB->get_results('SELECT ufdf_ID, ufdf_ufgp_ID
				FROM T_users__fielddefs
				ORDER BY ufdf_ufgp_ID, ufdf_ID');
        $userfield_order = 1;
        foreach ($userfields as $uf => $userfield) {
            if ($uf > 0) {
                if ($userfields[$uf - 1]->ufdf_ufgp_ID != $userfield->ufdf_ufgp_ID) {
                    // New group is starting, reset $userfield_order
                    $userfield_order = 1;
                }
            }
            $DB->query('UPDATE T_users__fielddefs
						SET ufdf_order = "' . $userfield_order . '"
						WHERE ufdf_ID = ' . $userfield->ufdf_ID);
            $userfield_order++;
        }
        // Change field type for Group 'Organization' (group_ID=4)
        $DB->query('UPDATE T_users__fielddefs
					SET ufdf_type = "word"
					WHERE ufdf_ufgp_ID = "4"');
        // Create a default additional info for administrator (user_ID=1)
        $DB->query('INSERT INTO T_users__fields ( uf_user_ID, uf_ufdf_ID, uf_varchar )
			VALUES ( 1, 200000, "Site administrator" ),
						 ( 1, 200000, "Moderator" ),
						 ( 1, 100000, "' . $baseurl . '" )');
        // Add Indexes
        $DB->query('ALTER TABLE T_users__fields
						ADD INDEX uf_ufdf_ID ( uf_ufdf_ID ),
						ADD INDEX uf_varchar ( uf_varchar ) ');
        task_end();
        task_begin('Upgrading permissions...');
        // Group permissions
        $DB->query('ALTER TABLE T_coll_group_perms
						ADD bloggroup_perm_own_cmts tinyint NOT NULL default 0 AFTER bloggroup_perm_edit_ts');
        // Set default values for Administrators & Privileged Bloggers groups
        $DB->query('UPDATE T_coll_group_perms
						SET bloggroup_perm_own_cmts = "1"
						WHERE bloggroup_group_ID IN ( 1, 2 )');
        // User permissions
        $DB->query('ALTER TABLE T_coll_user_perms
						ADD bloguser_perm_own_cmts tinyint NOT NULL default 0 AFTER bloguser_perm_edit_ts');
        task_end();
        set_upgrade_checkpoint('10500');
    }
    if ($old_db_version < 10600) {
        //  part 4
        // For create_default_regions() and create_default_subregions():
        require_once dirname(__FILE__) . '/_functions_create.php';
        task_begin('Renaming Countries table...');
        $DB->query('RENAME TABLE ' . $tableprefix . 'country TO T_regional__country');
        task_end();
        task_begin('Renaming Currencies table...');
        $DB->query('RENAME TABLE ' . $tableprefix . 'currency TO T_regional__currency');
        task_end();
        task_begin('Creating Regions table...');
        $DB->query('CREATE TABLE T_regional__region (
			rgn_ID        int(10) unsigned NOT NULL auto_increment,
			rgn_ctry_ID   int(10) unsigned NOT NULL,
			rgn_code      char(6) NOT NULL,
			rgn_name      varchar(40) NOT NULL,
			rgn_enabled   tinyint(1) NOT NULL DEFAULT 1,
			rgn_preferred tinyint(1) NOT NULL DEFAULT 0,
			PRIMARY KEY rgn_ID (rgn_ID),
			UNIQUE rgn_ctry_ID_code (rgn_ctry_ID, rgn_code)
		) ENGINE = innodb');
        task_end();
        create_default_regions();
        task_begin('Creating Sub-regions table...');
        $DB->query('CREATE TABLE T_regional__subregion (
			subrg_ID        int(10) unsigned NOT NULL auto_increment,
			subrg_rgn_ID    int(10) unsigned NOT NULL,
			subrg_code      char(6) NOT NULL,
			subrg_name      varchar(40) NOT NULL,
			subrg_enabled   tinyint(1) NOT NULL DEFAULT 1,
			subrg_preferred tinyint(1) NOT NULL DEFAULT 0,
			PRIMARY KEY subrg_ID (subrg_ID),
			UNIQUE subrg_rgn_ID_code (subrg_rgn_ID, subrg_code)
		) ENGINE = innodb');
        task_end();
        create_default_subregions();
        task_begin('Creating Cities table...');
        $DB->query('CREATE TABLE T_regional__city (
			city_ID         int(10) unsigned NOT NULL auto_increment,
			city_ctry_ID    int(10) unsigned NOT NULL,
			city_rgn_ID     int(10) unsigned NULL,
			city_subrg_ID   int(10) unsigned NULL,
			city_postcode   char(12) NOT NULL,
			city_name       varchar(40) NOT NULL,
			city_enabled    tinyint(1) NOT NULL DEFAULT 1,
			city_preferred  tinyint(1) NOT NULL DEFAULT 0,
			PRIMARY KEY city_ID (city_ID),
			INDEX city_ctry_ID_postcode ( city_ctry_ID, city_postcode ),
			INDEX city_rgn_ID_postcode ( city_rgn_ID, city_postcode ),
			INDEX city_subrg_ID_postcode ( city_subrg_ID, city_postcode )
		) ENGINE = innodb');
        task_end();
        task_begin('Update Item Settings...');
        // Admin: full rights for all blogs (look 'ma, doing a natural join! :>)
        $query = "INSERT INTO T_items__item_settings( iset_item_ID, iset_name, iset_value )\n\t\t\t\t\t\tSELECT post_ID, 'hide_teaser', post_hideteaser\n\t\t\t\t\t\t\tFROM T_items__item";
        $DB->query($query);
        db_drop_col('T_items__item', 'post_hideteaser');
        task_end();
        task_begin('Upgrading hitlog table...');
        $DB->query("ALTER TABLE T_hitlog\n\t\t\t\t\t\tADD COLUMN hit_keyphrase VARCHAR(255) DEFAULT NULL AFTER hit_keyphrase_keyp_ID");
        task_end();
        task_begin('Upgrading track__keyphrase...');
        $DB->query("ALTER TABLE T_track__keyphrase\n\t\t\t\t\t\tADD COLUMN keyp_count_refered_searches INT UNSIGNED DEFAULT 0 AFTER keyp_phrase,\n\t\t\t\t\t\tADD COLUMN keyp_count_internal_searches INT UNSIGNED DEFAULT 0 AFTER keyp_count_refered_searches");
        task_end();
        task_begin('Droping table internal searches...');
        $DB->query("DROP TABLE T_logs__internal_searches");
        task_end();
        task_begin('Upgrading users table...');
        db_add_col('T_users', 'user_rgn_ID', 'int(10) unsigned NULL AFTER user_ctry_ID');
        db_add_col('T_users', 'user_subrg_ID', 'int(10) unsigned NULL AFTER user_rgn_ID');
        db_add_col('T_users', 'user_city_ID', 'int(10) unsigned NULL AFTER user_subrg_ID');
        task_end();
        task_begin('Upgrading hitlog table...');
        $DB->query('UPDATE T_hitlog
						SET hit_type = "rss",
							hit_agent_type = "unknown"
						WHERE hit_agent_type = "rss"');
        $DB->query("ALTER TABLE T_hitlog\n\t\t\t\t\t\t\t\tCHANGE COLUMN hit_agent_type hit_agent_type ENUM('robot','browser','unknown') DEFAULT 'unknown' NOT NULL");
        task_end();
        task_begin('Creating mail log table...');
        $DB->query('CREATE TABLE ' . $tableprefix . 'mail__log (
		  emlog_ID        INT(10) UNSIGNED NOT NULL auto_increment,
		  emlog_timestamp TIMESTAMP NOT NULL,
		  emlog_to        VARCHAR(255) DEFAULT NULL,
		  emlog_success   TINYINT(1) NOT NULL DEFAULT 0,
		  emlog_subject   VARCHAR(255) DEFAULT NULL,
		  emlog_headers   TEXT DEFAULT NULL,
		  emlog_message   TEXT DEFAULT NULL,
		  PRIMARY KEY     (emlog_ID)
		) ENGINE = myisam');
        task_end();
        set_upgrade_checkpoint('10600');
    }
    if ($old_db_version < 10700) {
        // part 5
        task_begin('Upgrading user notifications settings...');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "notify_published_comments", user_notify
							FROM T_users', 'Move notify settings from users to users_usersettings');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "notify_comment_moderation", user_notify_moderation
							FROM T_users', 'Move notify moderation settings from users to users_usersettings');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "enable_PM", 1
							FROM T_users
								WHERE user_allow_msgform = 1 OR user_allow_msgform = 3', 'Set enable PM on users_usersettings');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "enable_PM", 0
							FROM T_users
								WHERE user_allow_msgform = 0 OR user_allow_msgform = 2', 'Set enable PM on users_usersettings');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "enable_email", 1
							FROM T_users
								WHERE user_allow_msgform > 1', 'Set enable email true on users_usersettings');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "enable_email", 0
							FROM T_users
								WHERE user_allow_msgform < 2', 'Set enable email false on users_usersettings');
        db_drop_col('T_users', 'user_notify');
        db_drop_col('T_users', 'user_notify_moderation');
        db_drop_col('T_users', 'user_allow_msgform');
        task_end();
        task_begin('Upgrading Item table...');
        db_add_col('T_items__item', 'post_ctry_ID', 'INT(10) UNSIGNED NULL');
        db_add_col('T_items__item', 'post_rgn_ID', 'INT(10) UNSIGNED NULL');
        db_add_col('T_items__item', 'post_subrg_ID', 'INT(10) UNSIGNED NULL');
        db_add_col('T_items__item', 'post_city_ID', 'INT(10) UNSIGNED NULL');
        task_end();
        task_begin('Upgrading users table...');
        db_drop_col('T_users', 'user_postcode');
        // Previously obsoleted
        db_drop_col('T_users', 'user_idmode');
        task_end();
        task_begin('Upgrading users fields table...');
        db_add_col('T_users__fielddefs', 'ufdf_bubbletip', 'varchar(2000) NULL');
        task_end();
        task_begin('Creating table for groups of messaging contacts...');
        $DB->query("CREATE TABLE IF NOT EXISTS T_messaging__contact_groups (\n\t\t\tcgr_ID      int(10) unsigned NOT NULL auto_increment,\n\t\t\tcgr_user_ID int(10) unsigned NOT NULL,\n\t\t\tcgr_name    varchar(50) NOT NULL,\n\t\t\tPRIMARY KEY cgr_ID (cgr_ID)\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Creating table for group users of messaging contacts...');
        $DB->query("CREATE TABLE T_messaging__contact_groupusers (\n\t\t\tcgu_user_ID int(10) unsigned NOT NULL,\n\t\t\tcgu_cgr_ID  int(10) unsigned NOT NULL,\n\t\t\tPRIMARY KEY cgu_PK (cgu_user_ID, cgu_cgr_ID)\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Upgrading mail log table...');
        db_add_col($tableprefix . 'mail__log', 'emlog_user_ID', 'INT(10) UNSIGNED DEFAULT NULL AFTER emlog_timestamp');
        task_end();
        set_upgrade_checkpoint('10700');
    }
    if ($old_db_version < 10800) {
        // part 6 aka between "i1-i2" and "i2"
        task_begin('Upgrading users table, add user status...');
        db_add_col('T_users', 'user_status', 'enum( "activated", "autoactivated", "closed", "deactivated", "emailchanged", "new" ) NOT NULL default "new" AFTER user_validated');
        $update_user_status_query = 'UPDATE T_users SET user_status = ';
        // check if new users must activate their account. If users are not required to activate their account, then all existing users will be considerated as activated user.
        $new_users_must_validate = $DB->get_var('SELECT set_value FROM T_settings WHERE set_name = ' . $DB->quote('newusers_mustvalidate'));
        if ($new_users_must_validate || $new_users_must_validate == NULL) {
            // newusers_mustvalidate setting is set to true, or it is not set at all. If it is not set, we know that the default value is true!
            // set activated status only for validated users
            $update_user_status_query .= $DB->quote('activated');
            $update_user_status_query .= ' WHERE user_validated = 1';
        } else {
            $update_user_status_query .= $DB->quote('autoactivated');
        }
        // set activated status for corresponding users
        $DB->query($update_user_status_query);
        db_drop_col('T_users', 'user_validated');
        task_end();
        set_upgrade_checkpoint('10800');
    }
    if ($old_db_version < 10900) {
        // part 7 aka "i3"
        task_begin('Upgrading user settings table...');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "show_online", 0
							FROM T_users
								WHERE user_showonline = 0', 'Set show online on users_usersettings');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "user_ip", user_ip
							FROM T_users
								WHERE user_ip IS NOT NULL', 'Set user ip on users_usersettings');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "user_domain", user_domain
							FROM T_users
								WHERE user_domain IS NOT NULL', 'Set user domain on users_usersettings');
        $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
						SELECT user_ID, "user_browser", user_browser
							FROM T_users
								WHERE user_browser IS NOT NULL', 'Set user browser on users_usersettings');
        db_drop_col('T_users', 'user_showonline');
        db_drop_col('T_users', 'user_ip');
        db_drop_col('T_users', 'user_domain');
        db_drop_col('T_users', 'user_browser');
        task_end();
        task_begin('Upgrading user activation settings...');
        // Remove all last_activation_email timestamps because we will use date instead of them
        $DB->query('DELETE FROM T_users__usersettings WHERE uset_name = "last_activation_email"');
        task_end();
        task_begin('Upgrading Users table...');
        // Update user_status column add 'failedactivation' status
        $DB->query('ALTER TABLE T_users CHANGE user_status
					user_status enum( "activated", "autoactivated", "closed", "deactivated", "emailchanged", "failedactivation", "new" ) NOT NULL default "new"');
        db_add_col('T_users', 'user_created_fromIPv4', 'int(10) unsigned NOT NULL');
        db_add_col('T_users', 'user_email_dom_ID', 'int(10) unsigned NULL');
        $DB->query('ALTER TABLE T_users CHANGE dateYMDhour user_created_datetime DATETIME NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        db_add_col('T_users', 'user_reg_ctry_ID', 'int(10) unsigned NULL AFTER user_age_max');
        db_add_col('T_users', 'user_profileupdate_ts', 'TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP');
        $DB->query('ALTER TABLE T_users ADD INDEX user_email ( user_email )');
        task_end();
        task_begin('Renaming Email log table...');
        $DB->query('RENAME TABLE ' . $tableprefix . 'mail__log TO T_email__log');
        task_end();
        task_begin('Creating email returns table...');
        $DB->query("CREATE TABLE T_email__returns (\n\t\t\t  emret_ID        INT(10) UNSIGNED NOT NULL auto_increment,\n\t\t\t  emret_address   VARCHAR(255) DEFAULT NULL,\n\t\t\t  emret_errormsg  VARCHAR(255) DEFAULT NULL,\n\t\t\t  emret_timestamp TIMESTAMP NOT NULL,\n\t\t\t  emret_headers   TEXT DEFAULT NULL,\n\t\t\t  emret_message   TEXT DEFAULT NULL,\n\t\t\t  emret_errtype   CHAR(1) NOT NULL DEFAULT 'U',\n\t\t\t  PRIMARY KEY     (emret_ID)\n\t\t\t) ENGINE = myisam");
        task_end();
        task_begin('Upgrading general settings table...');
        $DB->query('ALTER TABLE T_settings CHANGE set_value set_value VARCHAR( 5000 ) NULL');
        task_end();
        task_begin('Upgrading sessions table...');
        db_add_col('T_sessions', 'sess_device', 'VARCHAR(8) NOT NULL DEFAULT \'\'');
        task_end();
        task_begin('Creating table for Antispam IP Ranges...');
        $DB->query("CREATE TABLE T_antispam__iprange (\n\t\t\taipr_ID         int(10) unsigned NOT NULL auto_increment,\n\t\t\taipr_IPv4start  int(10) unsigned NOT NULL,\n\t\t\taipr_IPv4end    int(10) unsigned NOT NULL,\n\t\t\taipr_IP_timestamp        datetime not null DEFAULT '2000-01-01 00:00:00',\n\t\t\taipr_user_count int(10) unsigned DEFAULT 0,\n\t\t\tPRIMARY KEY aipr_ID (aipr_ID)\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Upgrading base domains table...');
        $DB->query("ALTER TABLE T_basedomains CHANGE dom_type dom_type ENUM( 'unknown', 'normal', 'searcheng', 'aggregator', 'email' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'unknown'");
        $DB->query('ALTER TABLE T_basedomains DROP INDEX dom_name');
        $DB->query('ALTER TABLE T_basedomains DROP INDEX dom_type');
        $DB->query('ALTER TABLE T_basedomains ADD UNIQUE dom_type_name ( dom_type, dom_name )');
        task_end();
        /*** Update user_email_dom_ID for all already existing users ***/
        task_begin('Upgrading users email domains...');
        $DB->begin();
        // Get the users
        $uemails_SQL = new SQL();
        $uemails_SQL->SELECT('user_ID, user_email');
        $uemails_SQL->FROM('T_users');
        $users_emails = $DB->get_assoc($uemails_SQL->get());
        if (count($users_emails) > 0) {
            // Get all email domains
            $edoms_SQL = new SQL();
            $edoms_SQL->SELECT('dom_ID, dom_name');
            $edoms_SQL->FROM('T_basedomains');
            $edoms_SQL->WHERE('dom_type = \'email\'');
            $email_domains = $DB->get_assoc($edoms_SQL->get());
            // pre_dump( $email_domains );
            foreach ($users_emails as $user_ID => $user_email) {
                if (preg_match('#@(.+)#i', strtolower($user_email), $ematch)) {
                    // Get email domain from user's email address
                    $email_domain = $ematch[1];
                    $dom_ID = array_search($email_domain, $email_domains);
                    if (!$dom_ID) {
                        // Insert new email domain
                        $DB->query('INSERT INTO T_basedomains ( dom_type, dom_name )
							VALUES ( \'email\', ' . $DB->quote($email_domain) . ' )');
                        $dom_ID = $DB->insert_id;
                        // Memorize inserted domain to prevent duplicates
                        $email_domains[$dom_ID] = $email_domain;
                        // pre_dump( $dom_ID, $email_domain );
                    }
                    // Update user_email_dom_ID
                    $DB->query('UPDATE T_users
						SET user_email_dom_ID = ' . $DB->quote($dom_ID) . '
						WHERE user_ID = ' . $DB->quote($user_ID));
                }
            }
        }
        $DB->commit();
        task_end();
        task_begin('Upgrading users fields table...');
        // Drop index before increasing a size to avoid an error about "max key length is 767 bytes"
        $DB->query('ALTER TABLE T_users__fields DROP INDEX uf_varchar');
        // Modify field size
        $DB->query('ALTER TABLE T_users__fields CHANGE uf_varchar uf_varchar VARCHAR( 10000 ) NOT NULL');
        // Add index again with limited size in 255 because of utf8 == 765
        $DB->query('ALTER TABLE T_users__fields ADD INDEX uf_varchar ( uf_varchar(255) )');
        task_end();
        task_begin('Upgrading cron tasks table...');
        $DB->query('ALTER TABLE T_cron__task CHANGE ctsk_name ctsk_name VARCHAR(255) NOT NULL');
        task_end();
        task_begin('Upgrading comments table...');
        db_add_col('T_comments', 'comment_IP_ctry_ID', 'int(10) unsigned NULL AFTER comment_author_IP');
        task_end();
        task_begin('Creating table for Blocked Email Addreses...');
        $DB->query("CREATE TABLE {$tableprefix}email__blocked (\n\t\t\temblk_ID                    INT(10) UNSIGNED NOT NULL auto_increment,\n\t\t\temblk_address               VARCHAR(255) DEFAULT NULL,\n\t\t\temblk_status                ENUM ( 'unknown', 'warning', 'suspicious1', 'suspicious2', 'suspicious3', 'prmerror', 'spammer' ) NOT NULL DEFAULT 'unknown',\n\t\t\temblk_sent_count            INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\temblk_sent_last_returnerror INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\temblk_prmerror_count        INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\temblk_tmperror_count        INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\temblk_spamerror_count       INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\temblk_othererror_count      INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\temblk_last_sent_ts          TIMESTAMP NULL,\n\t\t\temblk_last_error_ts         TIMESTAMP NULL,\n\t\t\tPRIMARY KEY                 (emblk_ID),\n\t\t\tUNIQUE                      emblk_address (emblk_address)\n\t\t) ENGINE = myisam");
        task_end();
        task_begin('Upgrading email log table...');
        // Get old values of emlog_success field
        $SQL = new SQL();
        $SQL->SELECT('emlog_ID');
        $SQL->FROM('T_email__log');
        $SQL->WHERE('emlog_success = 0');
        $email_failed_logs = $DB->get_col($SQL->get());
        // Change a field emlog_success to new format
        $DB->query('ALTER TABLE T_email__log CHANGE emlog_success emlog_result ENUM ( "ok", "error", "blocked" ) NOT NULL DEFAULT "ok"');
        if (!empty($email_failed_logs)) {
            // Update only the failed email logs to new values
            // Do NOT update the success email logs, because we already have a result type 'ok' as default
            $DB->query('UPDATE T_email__log
					SET emlog_result = ' . $DB->quote('error') . '
				WHERE emlog_ID IN ( ' . $DB->quote($email_failed_logs) . ' )');
        }
        task_end();
        set_upgrade_checkpoint('10900');
    }
    if ($old_db_version < 10970) {
        // part 8/a trunk aka first part of "i4"
        task_begin('Upgrading Locales table...');
        db_add_col('T_locales', 'loc_transliteration_map', 'VARCHAR(10000) NOT NULL default \'\' AFTER loc_priority');
        task_end();
        task_begin('Upgrading general settings table...');
        $DB->query('UPDATE T_settings SET set_name = ' . $DB->quote('smart_view_count') . ' WHERE set_name = ' . $DB->quote('smart_hit_count'));
        // This query below was added later to turn OFF smart view counting on upgrade from v4 to v5 for better performance
        $DB->query('DELETE FROM T_settings WHERE set_name = ' . $DB->quote('smart_view_count'));
        task_end();
        task_begin('Upgrading sessions table...');
        $DB->query("UPDATE T_sessions SET sess_lastseen = concat( '2000-01-01 ', time( sess_lastseen ) )\n\t\t\t\t\t\tWHERE date( sess_lastseen ) = '1970-01-01'");
        $DB->query("ALTER TABLE T_sessions CHANGE COLUMN sess_lastseen sess_lastseen_ts TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT 'User last logged activation time. Value may be off by up to 60 seconds'");
        db_add_col('T_sessions', 'sess_start_ts', "TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00' AFTER sess_hitcount");
        $DB->query('UPDATE T_sessions SET sess_start_ts = TIMESTAMPADD( SECOND, -1, sess_lastseen_ts )');
        db_drop_col('T_sessions', 'sess_hitcount');
        task_end();
        task_begin('Upgrading users table...');
        db_add_col('T_users', 'user_lastseen_ts', 'TIMESTAMP NULL AFTER user_created_datetime');
        $DB->query('UPDATE T_users SET user_lastseen_ts = ( SELECT MAX( sess_lastseen_ts ) FROM T_sessions WHERE sess_user_ID = user_ID )');
        $DB->query('UPDATE T_users SET user_profileupdate_ts = user_created_datetime WHERE user_profileupdate_ts < user_created_datetime');
        $DB->query("ALTER TABLE T_users CHANGE COLUMN user_profileupdate_ts user_profileupdate_date DATE NOT NULL DEFAULT '2000-01-01' COMMENT 'Last day when the user has updated some visible field in his profile.'");
        task_end();
        task_begin('Updating versions table...');
        db_add_col('T_items__version', 'iver_ID', 'INT UNSIGNED NOT NULL FIRST');
        $DB->query('ALTER TABLE T_items__version DROP INDEX iver_itm_ID, ADD INDEX iver_ID_itm_ID ( iver_ID , iver_itm_ID )');
        task_end();
        task_begin('Upgrading messaging contact group users...');
        db_add_foreign_key('T_messaging__contact_groupusers', 'cgu_cgr_ID', 'T_messaging__contact_groups', 'cgr_ID', 'ON DELETE CASCADE');
        task_end();
        task_begin('Creating table for a latest version of the POT file...');
        $DB->query("CREATE TABLE T_i18n_original_string (\n\t\t\tiost_ID        int(10) unsigned NOT NULL auto_increment,\n\t\t\tiost_string    varchar(10000) NOT NULL default '',\n\t\t\tiost_inpotfile tinyint(1) NOT NULL DEFAULT 0,\n\t\t\tPRIMARY KEY (iost_ID)\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Creating table for a latest versions of the PO files...');
        $DB->query("CREATE TABLE T_i18n_translated_string (\n\t\t\titst_ID       int(10) unsigned NOT NULL auto_increment,\n\t\t\titst_iost_ID  int(10) unsigned NOT NULL,\n\t\t\titst_locale   varchar(20) NOT NULL default '',\n\t\t\titst_standard varchar(10000) NOT NULL default '',\n\t\t\titst_custom   varchar(10000) NULL,\n\t\t\titst_inpofile tinyint(1) NOT NULL DEFAULT 0,\n\t\t\tPRIMARY KEY (itst_ID)\n\t\t) ENGINE = innodb DEFAULT CHARSET = utf8");
        task_end();
        task_begin('Updating Antispam IP Ranges table...');
        db_add_col('T_antispam__iprange', 'aipr_status', 'enum( \'trusted\', \'suspect\', \'blocked\' ) NULL DEFAULT NULL');
        db_add_col('T_antispam__iprange', 'aipr_block_count', 'int(10) unsigned DEFAULT 0');
        $DB->query("ALTER TABLE T_antispam__iprange CHANGE COLUMN aipr_user_count aipr_user_count int(10) unsigned DEFAULT 0");
        task_end();
        set_upgrade_checkpoint('10970');
    }
    if ($old_db_version < 10975) {
        // part 8/b trunk aka first part of "i4"
        task_begin('Creating default antispam IP ranges... ');
        $DB->query('
			INSERT INTO T_antispam__iprange ( aipr_IPv4start, aipr_IPv4end, aipr_status )
			VALUES ( ' . $DB->quote(ip2int('127.0.0.0')) . ', ' . $DB->quote(ip2int('127.0.0.255')) . ', "trusted" ),
				( ' . $DB->quote(ip2int('10.0.0.0')) . ', ' . $DB->quote(ip2int('10.255.255.255')) . ', "trusted" ),
				( ' . $DB->quote(ip2int('172.16.0.0')) . ', ' . $DB->quote(ip2int('172.31.255.255')) . ', "trusted" ),
				( ' . $DB->quote(ip2int('192.168.0.0')) . ', ' . $DB->quote(ip2int('192.168.255.255')) . ', "trusted" )
			');
        task_end();
        set_upgrade_checkpoint('10975');
    }
    if ($old_db_version < 11000) {
        // part 8/c trunk aka first part of "i4"
        task_begin('Adding new countries...');
        // IGNORE is needed for upgrades from DB version 9970 or later
        $DB->query('INSERT IGNORE INTO T_regional__country ( ctry_code, ctry_name, ctry_curr_ID ) VALUES ( \'ct\', \'Catalonia\', \'2\' )');
        task_end();
        task_begin('Upgrading message thread statuses table...');
        db_add_col('T_messaging__threadstatus', 'tsta_thread_leave_msg_ID', 'int(10) unsigned NULL DEFAULT NULL');
        task_end();
        task_begin('Upgrading Item Settings...');
        // Convert item custom fields to custom item settings ( move custom fields from T_items__item table to T_items__item_settings table )
        $query = "INSERT INTO T_items__item_settings( iset_item_ID, iset_name, iset_value ) ";
        for ($i = 1; $i <= 8; $i++) {
            // For each custom fields:
            if ($i > 1) {
                $query .= ' UNION';
            }
            $field_name = $i > 5 ? 'varchar' . ($i - 5) : 'double' . $i;
            $query .= " SELECT post_ID, 'custom_" . $field_name . "', post_" . $field_name . "\n\t\t\t\t\t\t\tFROM T_items__item WHERE post_" . $field_name . " IS NOT NULL";
        }
        $DB->query($query);
        for ($i = 1; $i <= 5; $i++) {
            // drop custom double columns from items tabe
            db_drop_col('T_items__item', 'post_double' . $i);
        }
        for ($i = 1; $i <= 3; $i++) {
            // drop custom varchar columns from items tabe
            db_drop_col('T_items__item', 'post_varchar' . $i);
        }
        // Convert post_editor_code item field to item settings
        $DB->query('INSERT INTO T_items__item_settings ( iset_item_ID, iset_name, iset_value )
						SELECT post_ID, "editor_code", post_editor_code
							FROM T_items__item
							WHERE post_editor_code IS NOT NULL');
        db_drop_col('T_items__item', 'post_editor_code');
        // Convert post_metadesc item field to item settings
        $DB->query('INSERT INTO T_items__item_settings ( iset_item_ID, iset_name, iset_value )
						SELECT post_ID, "post_metadesc", post_metadesc
							FROM T_items__item
							WHERE post_metadesc IS NOT NULL');
        db_drop_col('T_items__item', 'post_metadesc');
        // Convert and rename post_metakeywords item field to post_custom_headers item settings
        $DB->query('INSERT INTO T_items__item_settings ( iset_item_ID, iset_name, iset_value )
						SELECT post_ID, "post_custom_headers", post_metakeywords
							FROM T_items__item
							WHERE post_metakeywords IS NOT NULL');
        db_drop_col('T_items__item', 'post_metakeywords');
        task_end();
        task_begin('Upgrading items table...');
        // Drop not used column
        db_drop_col('T_items__item', 'post_commentsexpire');
        task_end();
        task_begin('Adding new video file types...');
        $ftyp = $DB->get_row('SELECT ftyp_ID, ftyp_extensions
									FROM T_filetypes
									WHERE ftyp_mimetype = "video/mp4"
									AND ftyp_extensions NOT LIKE "%f4v%"
									LIMIT 1');
        if ($ftyp) {
            // Add f4v extension to mp4 file type, if not exists
            $DB->query('UPDATE T_filetypes SET ftyp_extensions = "' . $DB->escape($ftyp->ftyp_extensions . ' f4v') . '"
							WHERE ftyp_ID = ' . $DB->quote($ftyp->ftyp_ID));
        }
        // Add flv file type if not exists
        if (!db_key_exists('T_filetypes', 'ftyp_extensions', '"flv"')) {
            $DB->query('INSERT INTO T_filetypes (ftyp_extensions, ftyp_name, ftyp_mimetype, ftyp_icon, ftyp_viewtype, ftyp_allowed)
				             VALUES ("flv", "Flash video file", "video/x-flv", "", "browser", "registered")', 'Add "flv" file type');
        }
        // Add swf file type if not exists
        if (!db_key_exists('T_filetypes', 'ftyp_extensions', '"swf"')) {
            $DB->query('INSERT INTO T_filetypes (ftyp_extensions, ftyp_name, ftyp_mimetype, ftyp_icon, ftyp_viewtype, ftyp_allowed)
				             VALUES ("swf", "Flash video file", "application/x-shockwave-flash", "", "browser", "registered")', 'Add "swf" file type');
        }
        task_end();
        task_begin('Upgrading custom item settings...');
        $DB->begin();
        // Convert latitude and longitude from custom setting to normal item settings
        // Get those blog ids where Latitude and Longitude are both set
        $result = $DB->get_col('SELECT cs_left.cset_coll_ID
									FROM T_coll_settings as cs_left
									INNER JOIN T_coll_settings as cs_right ON cs_left.cset_coll_ID = cs_right.cset_coll_ID
									WHERE cs_left.cset_name = "custom_double3" AND cs_left.cset_value = "Latitude" AND
										cs_right.cset_name = "custom_double4" AND cs_right.cset_value = "Longitude"');
        if ($result) {
            // blogs were found where Latitude and Longitude custom fields were set for google maps plugin
            // Set "Show location coordinates" on where Latitude and Longitude were set
            $query_values = '( ' . implode(', "show_location_coordinates", 1 ), ( ', $result) . ', "show_location_coordinates", 1 )';
            $DB->query('INSERT INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
							VALUES ' . $query_values);
            $coll_ids = implode(', ', $result);
            // Update latitude Item settings
            $DB->query('UPDATE T_items__item_settings SET iset_name = "latitude"
							WHERE iset_name = "custom_double3" AND iset_item_ID IN (
								SELECT post_ID FROM T_items__item
								INNER JOIN T_categories ON post_main_cat_ID = cat_ID
								WHERE cat_blog_ID IN ( ' . $coll_ids . ' )
							)');
            // Update longitude Item settings
            $DB->query('UPDATE T_items__item_settings SET iset_name = "longitude"
							WHERE iset_name = "custom_double4" AND iset_item_ID IN (
								SELECT post_ID FROM T_items__item
								INNER JOIN T_categories ON post_main_cat_ID = cat_ID
								WHERE cat_blog_ID IN ( ' . $coll_ids . ' )
							)');
            // Delete proessed latitude & longitude custom fields from collection settings
            $DB->query('DELETE FROM T_coll_settings
						WHERE ( cset_name = "custom_double3" OR cset_name = "custom_double4" ) AND
							cset_coll_ID IN ( ' . $coll_ids . ' )');
        }
        $DB->commit();
        // End convert latitude and longitude
        $DB->begin();
        // Convert custom fields
        // Delete not used custom fields
        $DB->query('DELETE FROM T_coll_settings WHERE ( cset_value IS NULL OR cset_value = "" ) AND cset_name LIKE "custom\\_%"');
        // Set custom double fields count
        $DB->query('INSERT INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
						SELECT cset_coll_ID, "count_custom_double", COUNT( cset_name )
						FROM T_coll_settings
						WHERE cset_name LIKE "custom\\_double%"
						GROUP BY cset_coll_ID');
        // Set custom varchar fields count
        $DB->query('INSERT INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
						SELECT cset_coll_ID, "count_custom_varchar", COUNT( cset_name )
						FROM T_coll_settings
						WHERE cset_name LIKE "custom\\_varchar%"
						GROUP BY cset_coll_ID');
        // Select all custom fields from all blog, to create converted field values
        $result = $DB->get_results('SELECT cset_coll_ID as coll_ID, cset_name as name, cset_value as value
										FROM T_coll_settings
										WHERE cset_name LIKE "custom\\_%"
										ORDER BY cset_coll_ID, cset_name');
        if (!empty($result)) {
            // There are custom fields in blog settings
            $convert_field_values = '';
            $reorder_field_values = '';
            $old_prefix = "";
            $old_coll_ID = "";
            foreach ($result as $row) {
                // process each custom field
                $custom_id = uniqid('');
                $prefix = substr($row->name, 7, 6) === 'double' ? 'custom_double' : 'custom_varchar';
                // replace custom_double{N} and custom_varchar{N} values with a custom_id where N is number
                $convert_field_values .= '( ' . $row->coll_ID . ', "' . $row->name . '", "' . $custom_id . '" ), ';
                // add new custom_double_{customid} and custom_varchar_{customid} entries with the old correspinding custom field values
                $convert_field_values .= '( ' . $row->coll_ID . ', "' . $prefix . '_' . $custom_id . '", "' . $row->value . '" ), ';
                // create reorder values to replace e.g. custom_double2 to custom_double1 if custom_double1 doesn't exists yet
                $index = $old_prefix == $prefix && $old_coll_ID == $row->coll_ID ? $index + 1 : 1;
                $reorder_field_values .= '( ' . $row->coll_ID . ', "' . $prefix . $index . '", "' . $custom_id . '" ), ';
                $old_prefix = $prefix;
                $old_coll_ID = $row->coll_ID;
            }
            $convert_field_values = substr($convert_field_values, 0, -2);
            $reorder_field_values = substr($reorder_field_values, 0, -2);
            // Convert custom fields in collection setting
            $DB->query('REPLACE INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
							VALUES ' . $convert_field_values);
            // Update double custom field name_ids in item settings table
            $DB->query('UPDATE T_items__item_settings SET iset_name = (
								SELECT CONCAT( "custom_double_", cset_value ) FROM T_coll_settings
									INNER JOIN T_categories ON cset_coll_ID = cat_blog_ID
									INNER JOIN T_items__item ON cat_ID = post_main_cat_ID
									WHERE cset_name = iset_name AND post_ID  = iset_item_ID )
							WHERE iset_name LIKE "custom\\_double%"');
            // Update varchar custom field name_ids in item settings table
            $DB->query('UPDATE T_items__item_settings SET iset_name = (
								SELECT CONCAT( "custom_varchar_", cset_value ) FROM T_coll_settings
									INNER JOIN T_categories ON cset_coll_ID = cat_blog_ID
									INNER JOIN T_items__item ON cat_ID = post_main_cat_ID
									WHERE cset_name = iset_name AND post_ID  = iset_item_ID )
							WHERE iset_name LIKE "custom\\_varchar%"');
            // Reorder custom fields in collection settings
            $DB->query('REPLACE INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
							VALUES ' . $reorder_field_values);
        }
        $DB->commit();
        // End convert custom fields
        task_end();
        task_begin('Convert group users permissions to pluggable permissions...');
        $DB->query('REPLACE INTO T_groups__groupsettings( gset_grp_ID, gset_name, gset_value )
						SELECT grp_ID, "perm_users", grp_perm_users
							FROM T_groups');
        db_drop_col('T_groups', 'grp_perm_users');
        task_end();
        task_begin('Update Post Types... ');
        $DB->query("REPLACE INTO T_items__type ( ptyp_ID, ptyp_name )\n\t\t\tVALUES ( 4000, 'Advertisement' )");
        task_end();
        task_begin('Update files table... ');
        db_add_col('T_files', 'file_hash', 'char(32) default NULL');
        task_end();
        task_begin('Create table for files voting...');
        $DB->query('CREATE TABLE ' . $tableprefix . 'files__vote (
				fvot_file_ID       int(11) UNSIGNED NOT NULL,
				fvot_user_ID       int(11) UNSIGNED NOT NULL,
				fvot_like          tinyint(1),
				fvot_inappropriate tinyint(1),
				fvot_spam          tinyint(1),
				primary key (fvot_file_ID, fvot_user_ID)
			) ENGINE = innodb');
        task_end();
        task_begin('Create table for users reporting...');
        $DB->query("CREATE TABLE T_users__reports (\n\t\t\turep_target_user_ID int(11) unsigned NOT NULL,\n\t\t\turep_reporter_ID    int(11) unsigned NOT NULL,\n\t\t\turep_status         enum( 'fake', 'guidelines', 'harass', 'spam', 'other' ),\n\t\t\turep_info           varchar(240),\n\t\t\turep_datetime\t\tdatetime NOT NULL,\n\t\t\tPRIMARY KEY ( urep_target_user_ID, urep_reporter_ID )\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Upgrading skins type...');
        $DB->query("ALTER TABLE T_skins__skin MODIFY COLUMN skin_type enum('normal','feed','sitemap','mobile','tablet') NOT NULL default 'normal'");
        task_end();
        task_begin('Upgrading blogs skins...');
        // Convert blog skin ID to blog settings
        $DB->query('INSERT INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
						SELECT blog_ID, "normal_skin_ID", blog_skin_ID
						FROM T_blogs');
        db_drop_col('T_blogs', 'blog_skin_ID');
        task_end();
        task_begin('Update categories table... ');
        db_add_col('T_categories', 'cat_meta', 'tinyint(1) NOT NULL DEFAULT 0');
        db_add_col('T_categories', 'cat_lock', 'tinyint(1) NOT NULL DEFAULT 0');
        task_end();
        task_begin('Plugin settings update...');
        $all_blog_ids = $DB->get_col('SELECT blog_ID FROM T_blogs');
        $plugin_ids = $DB->get_assoc('SELECT pset_plug_ID, pset_value FROM T_pluginsettings WHERE pset_name = "render_comments"');
        $insert_values = '';
        foreach ($all_blog_ids as $blog_ID) {
            foreach ($plugin_ids as $plugin_ID => $setting_value) {
                $apply_comment_rendering = $setting_value ? 'stealth' : 'never';
                $insert_values .= '( ' . $blog_ID . ', "plugin' . $plugin_ID . '_coll_apply_comment_rendering", "' . $apply_comment_rendering . '" ),';
            }
        }
        if (!empty($insert_values)) {
            $DB->query('INSERT INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
						VALUES ' . substr($insert_values, 0, strlen($insert_values) - 1));
        }
        $DB->query('DELETE FROM T_pluginsettings WHERE pset_name = "render_comments"');
        task_end();
        task_begin('Creating comment prerendering cache table...');
        $DB->query("CREATE TABLE T_comments__prerendering (\n\t\t\tcmpr_cmt_ID INT(11) UNSIGNED NOT NULL,\n\t\t\tcmpr_format ENUM('htmlbody','entityencoded','xml','text') NOT NULL,\n\t\t\tcmpr_renderers TEXT NOT NULL,\n\t\t\tcmpr_content_prerendered MEDIUMTEXT NULL,\n\t\t\tcmpr_datemodified TIMESTAMP NOT NULL,\n\t\t\tPRIMARY KEY (cmpr_cmt_ID, cmpr_format)\n\t\t) ENGINE = innodb");
        db_add_col('T_comments', 'comment_renderers', "TEXT NOT NULL AFTER comment_content");
        $DB->query('UPDATE T_comments SET comment_renderers = "default"');
        task_end();
        task_begin('Upgrading plugins table...');
        db_drop_col('T_plugins', 'plug_apply_rendering');
        task_end();
        task_begin('Upgrading Auto_P plugin...');
        $blog_settings = $DB->get_assoc('SELECT cset_coll_ID, cset_value FROM T_coll_settings WHERE cset_name = "comment_autobr"');
        $insert_values = array();
        $plugin_ids = $DB->get_col('SELECT plug_ID FROM T_plugins WHERE plug_code = "b2WPAutP"');
        foreach ($blog_settings as $blog_ID => $blog_setting_value) {
            foreach ($plugin_ids as $plugin_ID) {
                switch ($blog_setting_value) {
                    case 'never':
                        $apply_comment_rendering = 'never';
                        break;
                    case 'optional':
                        $apply_comment_rendering = 'opt-out';
                        break;
                    case 'always':
                        $apply_comment_rendering = 'stealth';
                        break;
                    default:
                        break 2;
                }
                $insert_values[] = '( ' . $blog_ID . ', "plugin' . $plugin_ID . '_coll_apply_comment_rendering", "' . $apply_comment_rendering . '" )';
            }
        }
        if (count($insert_values) > 0) {
            $DB->query('REPLACE INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
						VALUES ' . implode(',', $insert_values));
        }
        $DB->query('DELETE FROM T_coll_settings WHERE cset_name = "comment_autobr"');
        $DB->query('UPDATE T_comments SET comment_content = REPLACE( REPLACE( comment_content, "<br>\\n", "\\n" ), "<br />\\n", "\\n" )');
        task_end();
        set_upgrade_checkpoint('11000');
    }
    if ($old_db_version < 11010) {
        // part 9 trunk aka second part of "i4"
        task_begin('Upgrading post statuses...');
        $DB->query("ALTER TABLE T_items__item CHANGE COLUMN post_status post_status enum('published','community','deprecated','protected','private','review','draft','redirected') NOT NULL default 'published'");
        $DB->query("ALTER TABLE T_items__version CHANGE COLUMN iver_status iver_status ENUM('published','community','deprecated','protected','private','review','draft','redirected') NULL");
        $DB->query("ALTER TABLE T_coll_user_perms CHANGE COLUMN bloguser_perm_poststatuses bloguser_perm_poststatuses set('review','draft','private','protected','deprecated','community','published','redirected') NOT NULL default ''");
        $DB->query("ALTER TABLE T_coll_group_perms CHANGE COLUMN bloggroup_perm_poststatuses bloggroup_perm_poststatuses set('review','draft','private','protected','deprecated','community','published','redirected') NOT NULL default ''");
        task_end();
        task_begin('Upgrading groups table...');
        $pbloggers_renamed_to_moderators = $DB->query('UPDATE T_groups SET grp_name = "Moderators" WHERE grp_ID = 2 AND grp_name = "Privileged Bloggers"');
        // Update administrators and moderators users coll setting permissions with new permissions
        // Note we can change moderators permission if the group name and ID was not changed after the original install
        $moderators_condition = $pbloggers_renamed_to_moderators ? ' OR bloggroup_group_ID = 2' : '';
        $DB->query("UPDATE T_coll_group_perms SET bloggroup_perm_poststatuses = 'published,community,deprecated,protected,private,review,draft' WHERE bloggroup_group_ID = 1" . $moderators_condition);
        // Change groups name
        $DB->query('UPDATE T_groups SET grp_name = "Trusted Users" WHERE grp_ID = 3 AND grp_name = "Bloggers"');
        $DB->query('UPDATE T_groups SET grp_name = "Normal Users" WHERE grp_ID = 4 AND grp_name = "Basic Users"');
        // Get "Misbehaving/Suspect Users" group ID
        $suspect_query = 'SELECT grp_ID
						FROM T_groups
						WHERE grp_name = "Misbehaving/Suspect Users"
						ORDER BY grp_ID DESC
						LIMIT 1';
        $suspect_group_ID = $DB->get_var($suspect_query);
        if (empty($suspect_group_ID)) {
            // suspect group doesn't exists, check spammers because probably it does not exists either
            $insert_values = '( "Misbehaving/Suspect Users" )';
            // Get "Spammers/Restricted Users" group ID
            $query = 'SELECT grp_ID
					FROM T_groups
					WHERE grp_name = "Spammers/Restricted Users"
					ORDER BY grp_ID DESC
					LIMIT 1';
            $spammers_group_ID = $DB->get_var($query);
            if (empty($spammers_group_ID)) {
                $insert_values .= ', ( "Spammers/Restricted Users" )';
            }
            // Insert two new group
            $DB->query('INSERT INTO T_groups ( grp_name )
						VALUES ' . $insert_values);
            $suspect_group_ID = $DB->get_var($suspect_query);
            if ($suspect_group_ID) {
                // Set coll setting permissions for Misbehaving/Suspect Users in Forums
                $query = "\n\t\t\t\t\tINSERT INTO T_coll_group_perms( bloggroup_blog_ID, bloggroup_group_ID, bloggroup_ismember,\n\t\t\t\t\t\tbloggroup_perm_poststatuses, bloggroup_perm_delpost, bloggroup_perm_edit_ts,\n\t\t\t\t\t\tbloggroup_perm_own_cmts, bloggroup_perm_vote_spam_cmts, bloggroup_perm_draft_cmts, bloggroup_perm_publ_cmts, bloggroup_perm_depr_cmts,\n\t\t\t\t\t\tbloggroup_perm_cats, bloggroup_perm_properties,\n\t\t\t\t\t\tbloggroup_perm_media_upload, bloggroup_perm_media_browse, bloggroup_perm_media_change )\n\t\t\t\t\tSELECT blog_ID, " . $suspect_group_ID . ", 1, 'review,draft', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n\t\t\t\t\t\tFROM T_blogs WHERE blog_ID = 5 AND blog_shortname = 'Forums'";
                $DB->query($query);
            }
        }
        task_end();
        task_begin('Upgrading blogs table...');
        db_add_col('T_blogs', 'blog_type', 'ENUM( "std", "photo", "group", "forum", "manual" ) DEFAULT "std" NOT NULL');
        task_end();
        task_begin('Upgrading comment statuses...');
        $DB->query("ALTER TABLE T_comments CHANGE COLUMN comment_status comment_status ENUM('published','community','deprecated','protected','private','review','draft','trash') DEFAULT 'published' NOT NULL");
        task_end();
        task_begin('Updating collection user/group permissions...');
        db_add_col('T_coll_user_perms', 'bloguser_perm_cmtstatuses', "set('review','draft','private','protected','deprecated','community','published') NOT NULL default '' AFTER bloguser_perm_vote_spam_cmts");
        db_add_col('T_coll_user_perms', 'bloguser_perm_edit_cmt', "ENUM('no','own','anon','lt','le','all') NOT NULL default 'no' AFTER bloguser_perm_cmtstatuses");
        db_add_col('T_coll_group_perms', 'bloggroup_perm_cmtstatuses', "set('review','draft','private','protected','deprecated','community','published') NOT NULL default '' AFTER bloggroup_perm_vote_spam_cmts");
        db_add_col('T_coll_group_perms', 'bloggroup_perm_edit_cmt', "ENUM('no','own','anon','lt','le','all') NOT NULL default 'no' AFTER bloggroup_perm_cmtstatuses");
        // Add access to those comment statuses for what user had before
        $DB->query('UPDATE T_coll_user_perms
					SET bloguser_perm_cmtstatuses = ( bloguser_perm_publ_cmts * 1 ) | ( bloguser_perm_depr_cmts * 4 ) | ( bloguser_perm_draft_cmts * 64 )');
        // Add access to all cmt statuses for those users which had edit permission on all comment statuses
        $DB->query('UPDATE T_coll_user_perms
					SET bloguser_perm_cmtstatuses = "published,community,deprecated,protected,private,review,draft", bloguser_perm_edit_cmt = "all"
					WHERE bloguser_perm_publ_cmts <> 0 AND bloguser_perm_depr_cmts <> 0 AND bloguser_perm_draft_cmts <> 0');
        // Add "lower then" edit permission to those users who had permission to edit published or draft comments
        $DB->query('UPDATE T_coll_user_perms
					SET bloguser_perm_edit_cmt = "lt"
					WHERE ( bloguser_perm_cmtstatuses & 65 ) != 0 AND bloguser_perm_edit_cmt = "no"');
        // Add access to those comment statuses for what group had before
        $DB->query('UPDATE T_coll_group_perms
					SET bloggroup_perm_cmtstatuses = ( bloggroup_perm_publ_cmts * 1 ) | ( bloggroup_perm_depr_cmts * 4 ) | ( bloggroup_perm_draft_cmts * 64 )');
        // Add access to all cmt statuses for those groups which had edit permission on all comment statuses
        $DB->query('UPDATE T_coll_group_perms
					SET bloggroup_perm_cmtstatuses = "published,community,deprecated,protected,private,review,draft", bloggroup_perm_edit_cmt = "all"
					WHERE bloggroup_perm_publ_cmts <> 0 AND bloggroup_perm_depr_cmts <> 0 AND bloggroup_perm_draft_cmts <> 0');
        // Add "lower then" edit permission to those groups who had permission to edit published or draft comments
        $DB->query('UPDATE T_coll_group_perms
					SET bloggroup_perm_edit_cmt = "lt"
					WHERE ( bloggroup_perm_cmtstatuses & 65 ) != 0 AND bloggroup_perm_edit_cmt = "no"');
        db_drop_col('T_coll_user_perms', 'bloguser_perm_draft_cmts');
        db_drop_col('T_coll_user_perms', 'bloguser_perm_publ_cmts');
        db_drop_col('T_coll_user_perms', 'bloguser_perm_depr_cmts');
        db_drop_col('T_coll_group_perms', 'bloggroup_perm_draft_cmts');
        db_drop_col('T_coll_group_perms', 'bloggroup_perm_publ_cmts');
        db_drop_col('T_coll_group_perms', 'bloggroup_perm_depr_cmts');
        db_add_col('T_coll_user_perms', 'bloguser_perm_delcmts', 'tinyint NOT NULL default 0 AFTER bloguser_perm_edit_ts');
        db_add_col('T_coll_group_perms', 'bloggroup_perm_delcmts', 'tinyint NOT NULL default 0 AFTER bloggroup_perm_edit_ts');
        // GRANT delete comment perms for moderators
        $DB->query('UPDATE T_coll_group_perms
					SET bloggroup_perm_delcmts = 1
					WHERE bloggroup_perm_edit_cmt = "le" OR bloggroup_perm_edit_cmt = "all"');
        $DB->query("ALTER TABLE T_coll_user_perms CHANGE COLUMN bloguser_perm_own_cmts bloguser_perm_recycle_owncmts tinyint NOT NULL default 0");
        $DB->query("ALTER TABLE T_coll_group_perms CHANGE COLUMN bloggroup_perm_own_cmts bloggroup_perm_recycle_owncmts tinyint NOT NULL default 0");
        task_end();
        task_begin('Updating blogs settings...');
        $DB->query('UPDATE T_coll_settings SET cset_value = "blog" WHERE cset_name = "enable_goto_blog" AND cset_value = "1"');
        $DB->query('UPDATE T_coll_settings SET cset_value = "no" WHERE cset_name = "enable_goto_blog" AND cset_value = "0"');
        task_end();
        set_upgrade_checkpoint('11010');
    }
    if ($old_db_version < 11020) {
        // part 10 trunk aka third part of "i4"
        task_begin('Upgrading users table...');
        // Get all users with defined IPs
        $users_SQL = new SQL();
        $users_SQL->SELECT('user_ID, user_created_fromIPv4');
        $users_SQL->FROM('T_users');
        $users_SQL->WHERE('user_created_fromIPv4 IS NOT NULL');
        $users_SQL->WHERE_and('user_created_fromIPv4 != ' . $DB->quote(ip2int('0.0.0.0')));
        $users_SQL->WHERE_and('user_created_fromIPv4 != ' . $DB->quote(ip2int('127.0.0.1')));
        $users = $DB->get_assoc($users_SQL->get());
        // Get user's IPs from settings table
        $settings_SQL = new SQL();
        $settings_SQL->SELECT('uset_user_ID, uset_value');
        $settings_SQL->FROM('T_users__usersettings');
        $settings_SQL->WHERE('uset_name = "user_ip"');
        if (count($users) > 0) {
            // Get IPs only for users which have not IP in T_users table
            $settings_SQL->WHERE_and('uset_user_ID NOT IN (' . $DB->quote(array_keys($users)) . ')');
        }
        $settings = $DB->get_assoc($settings_SQL->get());
        if (count($users) > 0 || count($settings) > 0) {
            $users_settings_insert_sql = array();
            foreach ($users as $user_ID => $user_IP) {
                $users_settings_insert_sql[] = '( ' . $DB->quote($user_ID) . ', "created_fromIPv4", ' . $DB->quote($user_IP) . ' )';
            }
            foreach ($settings as $user_ID => $user_IP) {
                $users_settings_insert_sql[] = '( ' . $DB->quote($user_ID) . ', "created_fromIPv4", ' . $DB->quote(ip2int($user_IP)) . ' )';
            }
            // Insert IPs values into settings table
            $DB->query('INSERT INTO T_users__usersettings ( uset_user_ID, uset_name, uset_value )
				VALUES ' . implode(', ', $users_settings_insert_sql));
        }
        // Remove old IPs from settings table
        $DB->query('DELETE FROM T_users__usersettings
			WHERE uset_name = "user_ip"');
        db_drop_col('T_users', 'user_created_fromIPv4');
        task_end();
        set_upgrade_checkpoint('11020');
    }
    if ($old_db_version < 11025) {
        // part 11 trunk aka fourth part of "i4"
        task_begin('Upgrading items table...');
        $DB->query("UPDATE T_items__item SET post_datecreated = concat( '2000-01-01 ', time( post_datecreated ) )\n\t\t\t\t\t\tWHERE date( post_datecreated ) = '1970-01-01'");
        $DB->query("UPDATE T_items__item SET post_datemodified = concat( '2000-01-01 ', time( post_datemodified ) )\n\t\t\t\t\t\tWHERE date( post_datemodified ) = '1970-01-01'");
        $DB->query("ALTER TABLE T_items__item CHANGE COLUMN post_datecreated post_datecreated TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00'");
        $DB->query("ALTER TABLE T_items__item CHANGE COLUMN post_datemodified post_datemodified TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00'");
        db_add_col('T_items__item', 'post_last_touched_ts', "TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00' AFTER post_datemodified");
        $DB->query('UPDATE T_items__item SET post_last_touched_ts = post_datemodified');
        task_end();
        /*
         * ADD UPGRADES FOR i4 BRANCH __ABOVE__ IN THIS BLOCK.
         *
         * This part will be included in trunk and i4 branches
         */
        set_upgrade_checkpoint('11025');
    }
    // In some upgrade versions ( currently only in "i5" ) we would like to create profile pictures links from the user's files in the profile pictures folder
    // To be able to do that we need an up to date database version, so we will create profile pictures after the ugrade script run successfully.
    // Set this $create_profile_picture_links to true only in those upgrade block where it's required.
    $create_profile_picture_links = false;
    if ($old_db_version < 11100) {
        // part 12 trunk aka "i5"
        task_begin('Update links table...');
        db_add_col('T_links', 'link_usr_ID', 'int(11) unsigned  NULL COMMENT "Used for linking files to users (user profile picture)" AFTER link_cmt_ID');
        db_add_index('T_links', 'link_usr_ID', 'link_usr_ID');
        task_end();
        task_begin('Creating links for users profile pictures...');
        // Create links for main profile pictures
        $link_create_date = date2mysql(time());
        $DB->query('INSERT INTO T_links( link_datecreated, link_datemodified, link_usr_ID, link_file_ID, link_position, link_order )
						SELECT ' . $DB->quote($link_create_date) . ', ' . $DB->quote($link_create_date) . ', user_ID, user_avatar_file_ID, "", 1
						FROM T_users
						WHERE user_avatar_file_ID IS NOT NULL');
        // Set $create_profile_picture_links to true to create links for all files from the users profile_pictures folder
        $create_profile_picture_links = true;
        task_end();
        task_begin('Upgrading custom item settings...');
        $DB->begin();
        // Add names for custom fields
        // Select all custom fields from all blogs, to create field names
        $result = $DB->get_results('SELECT cset_coll_ID as coll_ID, cset_name as name, cset_value as value
										FROM T_coll_settings
										WHERE cset_name LIKE "custom\\_double\\_%"
										   OR cset_name LIKE "custom\\_varchar\\_%"
										ORDER BY cset_coll_ID, cset_name');
        if (!empty($result)) {
            // There are custom fields in blog settings
            $insert_field_names = '';
            foreach ($result as $row) {
                // process each custom field
                $field_guid = preg_replace('/^custom_(double|varchar)_([a-f0-9\\-]+)$/', '$2', $row->name);
                // Replace special chars/umlauts, if we can convert charsets:
                load_funcs('locales/_charset.funcs.php');
                $field_name = strtolower(preg_replace('/[^a-z0-9\\-_]+/i', '_', $row->value));
                $field_name = replace_special_chars($field_name);
                $insert_field_names .= '( ' . $row->coll_ID . ', "custom_fname_' . $field_guid . '", "' . $field_name . '" ), ';
            }
            // Insert names for custom fields in collection settings
            $DB->query('INSERT INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
							VALUES ' . substr($insert_field_names, 0, -2));
        }
        $DB->commit();
        // End adding of names for custom fields
        task_end();
        task_begin('Upgrading comments table...');
        db_add_index('T_comments', 'comment_status', 'comment_status');
        task_end();
        set_upgrade_checkpoint('11100');
    }
    if ($old_db_version < 11110) {
        // part 13 trunk aka second part of "i5"
        // Add new settings for antispam groups
        $antispam_group_settings = $DB->get_assoc('SELECT set_name, set_value
			 FROM T_settings
			WHERE set_name IN ( ' . $DB->quote(array('antispam_suspicious_group', 'antispam_trust_groups')) . ')');
        if (count($antispam_group_settings) < 2) {
            // Insert new settings only if don't exist in DB
            task_begin('Updating general settings...');
            // Set antispam suspicious group
            if (!isset($antispam_group_settings['antispam_suspicious_group'])) {
                // Insert new value, Don't rewrite value if it already defined before
                $suspect_group_SQL = new SQL();
                $suspect_group_SQL->SELECT('grp_ID');
                $suspect_group_SQL->FROM('T_groups');
                $suspect_group_SQL->WHERE('grp_name = ' . $DB->quote('Misbehaving/Suspect Users'));
                $suspect_group_ID = $DB->get_var($suspect_group_SQL->get());
                if (!empty($suspect_group_ID)) {
                    // Save setting value
                    $DB->query('INSERT INTO T_settings ( set_name, set_value ) VALUES
							( ' . $DB->quote('antispam_suspicious_group') . ', ' . $DB->quote($suspect_group_ID) . ' )');
                }
            }
            // Set antispam trust groups
            if (!isset($antispam_group_settings['antispam_trust_groups'])) {
                // Insert new value, Don't rewrite value if it already defined before
                $trust_groups = array('Administrators', 'Moderators', 'Trusted Users', 'Spammers/Restricted Users');
                $trust_groups_SQL = new SQL();
                $trust_groups_SQL->SELECT('grp_ID');
                $trust_groups_SQL->FROM('T_groups');
                $trust_groups_SQL->WHERE('grp_name IN ( ' . $DB->quote($trust_groups) . ')');
                $trust_groups_IDs = $DB->get_col($trust_groups_SQL->get());
                if (!empty($trust_groups_IDs)) {
                    // Save setting value
                    $DB->query('INSERT INTO T_settings ( set_name, set_value ) VALUES
							( ' . $DB->quote('antispam_trust_groups') . ', ' . $DB->quote(implode(',', $trust_groups_IDs)) . ' )');
                }
            }
            task_end();
        }
        set_upgrade_checkpoint('11110');
    }
    if ($old_db_version < 11200) {
        // part 14 trunk aka "i6"
        task_begin('Upgrading comments table...');
        db_add_col('T_comments', 'comment_last_touched_ts', "TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00' AFTER comment_date");
        $DB->query('UPDATE T_comments
		                SET comment_last_touched_ts = comment_date');
        task_end();
        task_begin('Convert email addresses to lowercase... ');
        $DB->query('UPDATE T_users SET user_email = LOWER( user_email )');
        $DB->query('UPDATE ' . $tableprefix . 'email__blocked SET emblk_address = LOWER( emblk_address )');
        $DB->query('UPDATE T_email__returns SET emret_address = LOWER( emret_address )');
        $DB->query('UPDATE T_email__log SET emlog_to = LOWER( emlog_to )');
        $DB->query('UPDATE T_comments
			  SET comment_author_email = LOWER( comment_author_email )
			WHERE comment_author_email IS NOT NULL');
        task_end();
        task_begin('Upgrading blogs table...');
        db_add_col('T_blogs', 'blog_order', 'int(11) NULL DEFAULT NULL');
        $DB->query('UPDATE T_blogs
		                SET blog_order = blog_ID');
        task_end();
        task_begin('Updating general settings...');
        $site_skins_enabled = $DB->get_var('SELECT set_value
			 FROM T_settings
			WHERE set_name = ' . $DB->quote('site_skins_enabled'));
        if (is_null($site_skins_enabled)) {
            // Insert new setting to disable site skins
            $DB->query('INSERT INTO T_settings ( set_name, set_value )
				VALUES ( ' . $DB->quote('site_skins_enabled') . ', ' . $DB->quote('0') . ' )');
        } elseif ($site_skins_enabled == '1') {
            // Disable site skins if it is enabled
            $DB->query('UPDATE T_settings
				  SET set_value = ' . $DB->quote('0') . '
				WHERE set_name = ' . $DB->quote('site_skins_enabled'));
        }
        task_end();
        task_begin('Upgrading blogs table...');
        db_add_col('T_blogs', 'blog_favorite', 'TINYINT(1) NOT NULL DEFAULT 1');
        task_end();
        task_begin('Upgrade table of base domains... ');
        $DB->query("ALTER TABLE T_basedomains CHANGE COLUMN dom_status dom_status ENUM('unknown','trusted','suspect','blocked') NOT NULL DEFAULT 'unknown'");
        task_end();
        task_begin('Create table for file links voting... ');
        $DB->query('CREATE TABLE ' . $tableprefix . 'links__vote (
				lvot_link_ID       int(11) UNSIGNED NOT NULL,
				lvot_user_ID       int(11) UNSIGNED NOT NULL,
				lvot_like          tinyint(1),
				lvot_inappropriate tinyint(1),
				lvot_spam          tinyint(1),
				primary key (lvot_link_ID, lvot_user_ID)
			) ENGINE = innodb');
        // Convert all file votes to link votes
        $DB->query('INSERT INTO ' . $tableprefix . 'links__vote ( lvot_link_ID, lvot_user_ID, lvot_like, lvot_inappropriate, lvot_spam )
						SELECT link_ID, fvot_user_ID, fvot_like, fvot_inappropriate, fvot_spam
						FROM ' . $tableprefix . 'files__vote
						LEFT JOIN T_links ON link_file_ID = fvot_file_ID
						WHERE link_ID IS NOT NULL');
        // Delete old file voting table
        $DB->query('DROP TABLE IF EXISTS ' . $tableprefix . 'files__vote');
        task_end();
        task_begin('Create table for goal categories... ');
        $DB->query('CREATE TABLE T_track__goalcat (
				gcat_ID     int(10) unsigned NOT NULL auto_increment,
				gcat_name   varchar(50) default NULL,
				gcat_color  char(7) default NULL,
				PRIMARY KEY (gcat_ID)
			) ENGINE = myisam');
        // Insert default goal category
        $DB->query('INSERT INTO T_track__goalcat ( gcat_name, gcat_color )
			VALUES ( ' . $DB->quote('Default') . ', ' . $DB->quote('#999999') . ' )');
        $default_goalcat_ID = $DB->insert_id;
        db_add_col('T_track__goal', 'goal_gcat_ID', 'int(10) unsigned NOT NULL DEFAULT "' . $default_goalcat_ID . '" AFTER goal_ID');
        $DB->query('ALTER TABLE T_track__goal
			CHANGE goal_gcat_ID goal_gcat_ID int(10) unsigned NOT NULL');
        task_end();
        // This task was not required, but we would like to make sure that we have future proof link_datecreated and link_datemodified fields.
        // There were previous versions, when these fields were set to '1970-01-01' because the $localtimenow was not initialized during the install script
        task_begin('Update links table...');
        $DB->query("UPDATE T_links SET link_datecreated = concat( '2000-01-01 ', time( link_datecreated ) )\n\t\t\t\t\t\tWHERE date( link_datecreated ) = '1970-01-01'");
        $DB->query("UPDATE T_links SET link_datemodified = concat( '2000-01-01 ', time( link_datemodified ) )\n\t\t\t\t\t\tWHERE date( link_datemodified ) = '1970-01-01'");
        task_end();
        task_begin('Upgrading Blogs table...');
        $DB->query('ALTER TABLE T_blogs CHANGE blog_description blog_shortdesc varchar(250) NULL default ""');
        task_end();
        task_begin('Upgrading Comments table...');
        $DB->query('ALTER TABLE T_comments
			CHANGE comment_post_ID   comment_item_ID        int(11) unsigned NOT NULL default 0,
			CHANGE comment_author_ID comment_author_user_ID int unsigned NULL default NULL');
        $DB->query('ALTER TABLE T_comments
			DROP INDEX comment_post_ID');
        $DB->query('ALTER TABLE T_comments
			ADD KEY comment_item_ID ( comment_item_ID )');
        task_end();
        task_begin('Upgrading Files table...');
        $DB->query('ALTER TABLE T_files
			DROP INDEX file,
			ADD COLUMN file_path_hash char(32) default NULL');
        // Change file path length to the max allowed value
        $DB->query("ALTER TABLE T_files CHANGE COLUMN file_path file_path VARCHAR(767) NOT NULL DEFAULT ''");
        $DB->query('UPDATE T_files SET file_path_hash = MD5( CONCAT( file_root_type, file_root_ID, file_path ) )');
        $DB->query('ALTER TABLE T_files ADD UNIQUE file_path (file_path_hash)');
        task_end();
        task_begin('Create table for email campaigns... ');
        $DB->query('CREATE TABLE T_email__campaign (
			ecmp_ID          INT NOT NULL AUTO_INCREMENT,
			ecmp_date_ts     TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\',
			ecmp_name        VARCHAR(255) NOT NULL,
			ecmp_email_title VARCHAR(255) NULL,
			ecmp_email_html  TEXT NULL,
			ecmp_email_text  TEXT NULL,
			ecmp_sent_ts     TIMESTAMP NULL,
			PRIMARY KEY      (ecmp_ID)
			) ENGINE = myisam');
        task_end();
        task_begin('Create table for email campaign send data... ');
        $DB->query('CREATE TABLE T_email__campaign_send (
			csnd_camp_ID  INT(11) UNSIGNED NOT NULL,
			csnd_user_ID  INT(11) UNSIGNED NOT NULL,
			csnd_emlog_ID INT(11) UNSIGNED NULL,
			PRIMARY KEY   csnd_PK ( csnd_camp_ID, csnd_user_ID )
			) ENGINE = myisam');
        task_end();
        task_begin('Rename table "email blocked" to "email address"... ');
        $DB->query('RENAME TABLE ' . $tableprefix . 'email__blocked TO T_email__address');
        $DB->query("ALTER TABLE T_email__address\n\t\t\tCHANGE emblk_ID                    emadr_ID                    INT(10) UNSIGNED NOT NULL auto_increment,\n\t\t\tCHANGE emblk_address               emadr_address               VARCHAR(255) DEFAULT NULL,\n\t\t\tCHANGE emblk_status                emadr_status                ENUM ( 'unknown', 'warning', 'suspicious1', 'suspicious2', 'suspicious3', 'prmerror', 'spammer' ) NOT NULL DEFAULT 'unknown',\n\t\t\tCHANGE emblk_sent_count            emadr_sent_count            INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\tCHANGE emblk_sent_last_returnerror emadr_sent_last_returnerror INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\tCHANGE emblk_prmerror_count        emadr_prmerror_count        INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\tCHANGE emblk_tmperror_count        emadr_tmperror_count        INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\tCHANGE emblk_spamerror_count       emadr_spamerror_count       INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\tCHANGE emblk_othererror_count      emadr_othererror_count      INT(10) UNSIGNED NOT NULL DEFAULT 0,\n\t\t\tCHANGE emblk_last_sent_ts          emadr_last_sent_ts          TIMESTAMP NULL,\n\t\t\tCHANGE emblk_last_error_ts         emadr_last_error_ts         TIMESTAMP NULL");
        $DB->query("ALTER TABLE T_email__address\n\t\t\tADD UNIQUE emadr_address ( emadr_address )");
        $DB->query("ALTER TABLE T_email__address\n\t\t\tDROP INDEX emblk_address");
        task_end();
        // Add new email status 'redemption'
        task_begin('Upgrading table of email addresses...');
        $DB->query("ALTER TABLE T_email__address\n\t\t\tCHANGE emadr_status   emadr_status ENUM ( 'unknown', 'redemption', 'warning', 'suspicious1', 'suspicious2', 'suspicious3', 'prmerror', 'spammer' ) NOT NULL DEFAULT 'unknown'");
        task_end();
        task_begin('Upgrading blog-group permissions table...');
        db_add_col('T_coll_group_perms', 'bloggroup_can_be_assignee', 'tinyint NOT NULL default 0 AFTER bloggroup_ismember');
        $DB->query('UPDATE T_coll_group_perms
			  SET bloggroup_can_be_assignee = 1
			WHERE bloggroup_group_ID IN ( 1, 2 )');
        task_end();
        task_begin('Upgrading blog-user permissions table...');
        db_add_col('T_coll_user_perms', 'bloguser_can_be_assignee', 'tinyint NOT NULL default 0 AFTER bloguser_ismember');
        task_end();
        task_begin('Dropping obsolete columns from table Links...');
        $DB->query('ALTER TABLE T_links
									DROP COLUMN link_external_url,
									DROP COLUMN link_title,
									DROP COLUMN link_dest_itm_ID');
        task_end();
        // This task was added later to turn OFF smart view counting on upgrade from v5.0 to v5.1 for better performance
        task_begin('Turn off smart view counting...');
        $DB->query('DELETE FROM T_settings WHERE set_name = ' . $DB->quote('smart_view_count'));
        task_end();
        task_begin('Upgrading Posts table...');
        db_drop_col('T_items__item', 'post_views');
        task_end();
        task_begin('Upgrading Files table... ');
        $DB->query("ALTER TABLE T_files\n\t\t\tCHANGE COLUMN file_root_type file_root_type enum('absolute','user','collection','shared','skins','import') not null default 'absolute'");
        task_end();
        // Set flag to recreate autogenerated excerpts due to modifications on the excerpt generation
        // Note: We need to generate this in the end of the upgrade script, because the database must be up to date
        $recreate_autogenerated_excerpts = true;
        set_upgrade_checkpoint('11200');
    }
    if ($old_db_version < 11208) {
        // part 15.a trunk aka second part of "i6"
        // Note create a separate block for the hitlog upgrade because it may require very long time
        task_begin('Upgrade hitlog table...');
        $DB->query('ALTER TABLE T_hitlog
			CHANGE COLUMN hit_ID            hit_ID            INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
			CHANGE COLUMN hit_datetime      hit_datetime      TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\',
			CHANGE COLUMN hit_serprank      hit_serprank      SMALLINT UNSIGNED DEFAULT NULL,
			CHANGE COLUMN hit_blog_ID       hit_coll_ID       INT(10) UNSIGNED NULL DEFAULT NULL,
			CHANGE COLUMN hit_response_code hit_response_code SMALLINT DEFAULT NULL,
			ADD COLUMN hit_agent_ID SMALLINT UNSIGNED NULL DEFAULT NULL AFTER hit_agent_type');
        $DB->query('ALTER TABLE T_hitlog
			DROP INDEX hit_blog_ID');
        $DB->query('ALTER TABLE T_hitlog
			ADD KEY hit_coll_ID ( hit_coll_ID )');
        task_end();
        set_upgrade_checkpoint('11208');
    }
    if ($old_db_version < 11210) {
        // part 15.b trunk aka third part of "i6"
        task_begin('Updating widgets setting...');
        // Unset those widgets allow blockcache value which current settings allow blockcache but the caching is always forbidden on runtime;
        $DB->query('UPDATE T_widget
				SET wi_params = REPLACE( wi_params, \'s:16:"allow_blockcache";i:1\', \'s:16:"allow_blockcache";i:0\' )
				WHERE wi_params LIKE \'%s:16:"allow_blockcache";i:1%\' AND (
					wi_code = "user_tools" OR wi_code = "user_login" OR ( wi_code = "msg_menu_link" AND wi_params LIKE \'%s:9:"link_type";s:8:"messages"%\' )
					OR ( wi_code = "menu_link" AND ( wi_params LIKE \'%s:9:"link_type";s:5:"login"%\' OR wi_params LIKE \'%s:9:"link_type";s:8:"register"%\' ) )
					)');
        // Unset 'show_badge' setting in case of msg_menu_link widgets where the link_type is contacts
        $DB->query('UPDATE T_widget
				SET wi_params = REPLACE( wi_params, \'s:10:"show_badge";i:1\', \'s:10:"show_badge";i:0\' )
				WHERE wi_code = "msg_menu_link" AND wi_params LIKE \'%s:9:"link_type";s:8:"contacts"%\' AND wi_params LIKE \'%s:10:"show_badge";i:1%\'');
        task_end();
        task_begin('Updating files hash values...');
        $DB->query('ALTER TABLE T_files MODIFY COLUMN file_hash VARBINARY(32), MODIFY COLUMN file_path_hash VARBINARY(32)');
        $DB->query('UPDATE T_files SET file_hash = UNHEX( file_hash ), file_path_hash = UNHEX( file_path_hash )');
        $DB->query('ALTER TABLE T_files MODIFY COLUMN file_hash BINARY(16) default NULL, MODIFY COLUMN file_path_hash BINARY(16) default NULL');
        task_end();
        task_begin('Upgrading goals table...');
        $DB->query('ALTER TABLE T_track__goal
			ADD COLUMN goal_temp_redir_url varchar(255) default NULL AFTER goal_redir_url,
			ADD COLUMN goal_temp_start_ts  TIMESTAMP NULL            AFTER goal_temp_redir_url,
			ADD COLUMN goal_temp_end_ts    TIMESTAMP NULL            AFTER goal_temp_start_ts,
			ADD COLUMN goal_notes          TEXT DEFAULT NULL');
        task_end();
        set_upgrade_checkpoint('11210');
    }
    if ($old_db_version < 11220) {
        // part 16.a trunk aka fourth part of "i6"
        task_begin('Upgrading countries table...');
        $DB->query('ALTER TABLE T_regional__country
			ADD COLUMN ctry_status      enum( \'trusted\', \'suspect\', \'blocked\' ) NULL DEFAULT NULL,
			ADD COLUMN ctry_block_count int(10) unsigned DEFAULT 0');
        task_end();
        set_upgrade_checkpoint('11220');
    }
    if ($old_db_version < 11240) {
        // part 16.d trunk aka seventh part of "i6"
        task_begin('Updating general settings...');
        $DB->query('UPDATE T_settings SET
			set_name = CASE
				WHEN set_name = "user_closing_allow" THEN "account_close_enabled"
				WHEN set_name = "user_closing_intro" THEN "account_close_intro"
				WHEN set_name = "user_closing_reasons" THEN "account_close_reasons"
				WHEN set_name = "user_closing_byemsg" THEN "account_close_byemsg"
				ELSE set_name
			END');
        task_end();
        set_upgrade_checkpoint('11240');
    }
    if ($old_db_version < 11245) {
        // part 16.e trunk aka eighth part of "i6"
        task_begin('Updating Antispam IP Ranges table...');
        db_add_col('T_antispam__iprange', 'aipr_contact_email_count', 'int(10) unsigned DEFAULT 0 AFTER aipr_user_count');
        task_end();
        task_begin('Updating invalid locale settings...');
        $current_default_locale = $DB->get_var('SELECT set_value FROM T_settings WHERE set_name = "default_locale"');
        if (empty($current_default_locale)) {
            // The default locale is not set in the database, use the one from the config file
            global $default_locale;
            $current_default_locale = $default_locale;
        }
        if ($DB->get_var('SELECT loc_enabled FROM T_locales WHERE loc_locale = ' . $DB->quote($current_default_locale))) {
            // Update invalid user and collection locales to the default, but only if the default exists and it is enabled
            $DB->query('UPDATE T_users
				SET user_locale = ' . $DB->quote($current_default_locale) . '
				WHERE  user_locale NOT IN ( SELECT loc_locale FROM T_locales WHERE loc_enabled = 1 )');
            $DB->query('UPDATE T_blogs
				SET blog_locale = ' . $DB->quote($current_default_locale) . '
				WHERE  blog_locale NOT IN ( SELECT loc_locale FROM T_locales WHERE loc_enabled = 1 )');
        }
        task_end();
        set_upgrade_checkpoint('11245');
    }
    if ($old_db_version < 11250) {
        // part 16.f trunk aka ninth part of "i6"
        // Convert item content separators to new format
        load_funcs('tools/model/_dbmaintenance.funcs.php');
        dbm_convert_item_content_separators();
        set_upgrade_checkpoint('11250');
    }
    if ($old_db_version < 11255) {
        // part 16.g trunk aka tenth part of "i6"
        task_begin('Updating post types...');
        $DB->query("INSERT INTO T_items__type ( ptyp_ID, ptyp_name )\n\t\t\tVALUES ( 1400, 'Intro-Front' )");
        task_end();
        set_upgrade_checkpoint('11255');
    }
    if ($old_db_version < 11260) {
        // part 16.h trunk aka eleventh part of "i6"
        // This upgrade block updates all field collations from 'ascii_bin' to 'ascii_general_ci' except of slugs table.
        task_begin('Clean up comment emails...');
        $DB->query("UPDATE T_comments\n\t\t\t\t\t\tSET comment_author_email = CONVERT(comment_author_email USING ascii)");
        $DB->commit();
        task_end();
        task_begin('Convert the field collations from ascii_bin to ascii_general_ci... <br />');
        // fp> why would we need a transaction here?	$DB->begin();
        task_begin('- Converting skins table...');
        $DB->query("ALTER TABLE T_skins__skin\n\t\t\tMODIFY skin_type enum('normal','feed','sitemap','mobile','tablet') COLLATE ascii_general_ci NOT NULL default 'normal'");
        task_end();
        task_begin('- Converting blogs table...');
        $DB->query("ALTER TABLE T_blogs\n\t\t\tMODIFY blog_access_type    VARCHAR(10) COLLATE ascii_general_ci NOT NULL DEFAULT 'extrapath',\n\t\t\tMODIFY blog_urlname        VARCHAR(255) COLLATE ascii_general_ci NOT NULL DEFAULT 'urlname',\n\t\t\tMODIFY blog_media_location ENUM( 'default', 'subdir', 'custom', 'none' ) COLLATE ascii_general_ci DEFAULT 'default' NOT NULL,\n\t\t\tMODIFY blog_type           ENUM( 'std', 'photo', 'group', 'forum', 'manual' ) COLLATE ascii_general_ci DEFAULT 'std' NOT NULL");
        task_end();
        task_begin('- Converting blog settings table...');
        $DB->query('ALTER TABLE T_coll_settings
			MODIFY cset_name VARCHAR( 50 ) COLLATE ascii_general_ci NOT NULL');
        task_end();
        task_begin('- Converting widgets table...');
        $DB->query("ALTER TABLE {$tableprefix}widget\n\t\t\tMODIFY wi_type ENUM( 'core', 'plugin' ) COLLATE ascii_general_ci NOT NULL DEFAULT 'core',\n\t\t\tMODIFY wi_code VARCHAR(32) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting categories table...');
        $DB->query("ALTER TABLE T_categories\n\t\t\tMODIFY cat_urlname varchar(255) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting posts table...');
        $DB->query("ALTER TABLE T_items__item\n\t\t\tMODIFY post_status               enum('published','community','deprecated','protected','private','review','draft','redirected') COLLATE ascii_general_ci NOT NULL default 'published',\n\t\t\tMODIFY post_urltitle             VARCHAR(210) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY post_notifications_status ENUM('noreq','todo','started','finished') COLLATE ascii_general_ci NOT NULL DEFAULT 'noreq',\n\t\t\tMODIFY post_comment_status       ENUM('disabled', 'open', 'closed') COLLATE ascii_general_ci NOT NULL DEFAULT 'open',\n\t\t\tMODIFY post_renderers            TEXT COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting comments table...');
        $DB->query("ALTER TABLE T_comments\n\t\t\tMODIFY comment_type         enum('comment','linkback','trackback','pingback') COLLATE ascii_general_ci NOT NULL default 'comment',\n\t\t\tMODIFY comment_status       ENUM('published','community','deprecated','protected','private','review','draft','trash') COLLATE ascii_general_ci DEFAULT 'published' NOT NULL,\n\t\t\tMODIFY comment_author_email varchar(255) COLLATE ascii_general_ci NULL,\n\t\t\tMODIFY comment_author_IP    varchar(23) COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY comment_renderers    TEXT COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY comment_secret       CHAR(32) COLLATE ascii_general_ci NULL default NULL,\n\t\t\tMODIFY comment_notif_status ENUM('noreq','todo','started','finished') COLLATE ascii_general_ci NOT NULL DEFAULT 'noreq' COMMENT 'Have notifications been sent for this comment? How far are we in the process?'");
        task_end();
        task_begin('- Converting post prerendered contents table...');
        $DB->query("ALTER TABLE T_items__prerendering\n\t\t\tMODIFY itpr_format    ENUM('htmlbody','entityencoded','xml','text') COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY itpr_renderers TEXT COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting comment prerendered contents table...');
        $DB->query("ALTER TABLE T_comments__prerendering\n\t\t\tMODIFY cmpr_format    ENUM('htmlbody','entityencoded','xml','text') COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY cmpr_renderers TEXT COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting post versions table...');
        $DB->query("ALTER TABLE T_items__version\n\t\t\tMODIFY iver_status ENUM('published','community','deprecated','protected','private','review','draft','redirected') COLLATE ascii_general_ci NULL");
        task_end();
        task_begin('- Converting post settings table...');
        $DB->query("ALTER TABLE T_items__item_settings\n\t\t\tMODIFY iset_name varchar( 50 ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting user permissions table...');
        $DB->query("ALTER TABLE T_coll_user_perms\n\t\t\tMODIFY bloguser_perm_poststatuses set('review','draft','private','protected','deprecated','community','published','redirected') COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY bloguser_perm_edit         ENUM('no','own','lt','le','all','redirected') COLLATE ascii_general_ci NOT NULL default 'no',\n\t\t\tMODIFY bloguser_perm_cmtstatuses  set('review','draft','private','protected','deprecated','community','published') COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY bloguser_perm_edit_cmt     ENUM('no','own','anon','lt','le','all') COLLATE ascii_general_ci NOT NULL default 'no'");
        task_end();
        task_begin('- Converting group permissions table...');
        $DB->query("ALTER TABLE T_coll_group_perms\n\t\t\tMODIFY bloggroup_perm_poststatuses set('review','draft','private','protected','deprecated','community','published','redirected') COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY bloggroup_perm_edit         ENUM('no','own','lt','le','all','redirected') COLLATE ascii_general_ci NOT NULL default 'no',\n\t\t\tMODIFY bloggroup_perm_cmtstatuses  set('review','draft','private','protected','deprecated','community','published') COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY bloggroup_perm_edit_cmt     ENUM('no','own','anon','lt','le','all') COLLATE ascii_general_ci NOT NULL default 'no'");
        task_end();
        task_begin('- Converting links table...');
        $DB->query("ALTER TABLE T_links\n\t\t\tMODIFY link_position varchar(10) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting files table...');
        $DB->query("ALTER TABLE T_files\n\t\t\tMODIFY file_root_type enum('absolute','user','collection','shared','skins','import') COLLATE ascii_general_ci NOT NULL DEFAULT 'absolute'");
        task_end();
        task_begin('- Converting file types table...');
        $DB->query("ALTER TABLE T_filetypes\n\t\t\tMODIFY ftyp_extensions varchar(30) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY ftyp_viewtype   varchar(10) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY ftyp_allowed    enum('any','registered','admin') COLLATE ascii_general_ci NOT NULL default 'admin'");
        task_end();
        task_begin('- Converting sessions table...');
        $DB->query("ALTER TABLE T_sessions\n\t\t\tMODIFY sess_key       CHAR(32) COLLATE ascii_general_ci NULL,\n\t\t\tMODIFY sess_ipaddress VARCHAR(39) COLLATE ascii_general_ci NOT NULL DEFAULT '',\n\t\t\tMODIFY sess_device    VARCHAR(8) COLLATE ascii_general_ci NOT NULL DEFAULT ''");
        task_end();
        task_begin('- Converting domains table...');
        $DB->query("ALTER TABLE T_basedomains\n\t\t\tMODIFY dom_status ENUM('unknown','trusted','suspect','blocked') COLLATE ascii_general_ci NOT NULL DEFAULT 'unknown',\n\t\t\tMODIFY dom_type   ENUM('unknown','normal','searcheng','aggregator','email') COLLATE ascii_general_ci NOT NULL DEFAULT 'unknown'");
        task_end();
        task_begin('- Converting logs table...');
        $DB->query("ALTER TABLE T_hitlog\n\t\t\tMODIFY hit_ctrl         VARCHAR(30) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY hit_type         ENUM('standard','rss','admin','ajax', 'service') COLLATE ascii_general_ci DEFAULT 'standard' NOT NULL,\n\t\t\tMODIFY hit_referer_type ENUM('search','special','spam','referer','direct','self') COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY hit_remote_addr  VARCHAR(40) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY hit_agent_type   ENUM('robot','browser','unknown') COLLATE ascii_general_ci DEFAULT 'unknown' NOT NULL");
        task_end();
        task_begin('- Converting goal categories table...');
        $DB->query("ALTER TABLE T_track__goalcat\n\t\t\tMODIFY gcat_color  char(7) COLLATE ascii_general_ci default NULL");
        task_end();
        task_begin('- Converting groups table...');
        $DB->query("ALTER TABLE T_groups\n\t\t\tMODIFY grp_perm_blogs                  enum('user','viewall','editall') COLLATE ascii_general_ci NOT NULL default 'user',\n\t\t\tMODIFY grp_perm_xhtmlvalidation        VARCHAR(10) COLLATE ascii_general_ci NOT NULL default 'always',\n\t\t\tMODIFY grp_perm_xhtmlvalidation_xmlrpc VARCHAR(10) COLLATE ascii_general_ci NOT NULL default 'always',\n\t\t\tMODIFY grp_perm_stats                  enum('none','user','view','edit') COLLATE ascii_general_ci NOT NULL default 'none'");
        task_end();
        task_begin('- Converting group settings table...');
        $DB->query("ALTER TABLE T_groups__groupsettings\n\t\t\tMODIFY gset_name VARCHAR(30) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting settings table...');
        $DB->query("ALTER TABLE T_settings\n\t\t\tMODIFY set_name VARCHAR(30) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting cache table...');
        $DB->query("ALTER TABLE T_global__cache\n\t\t\tMODIFY cach_name VARCHAR(30) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting users table...');
        $DB->query("ALTER TABLE T_users\n\t\t\tMODIFY user_email           varchar(255) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY user_status          enum( 'activated', 'autoactivated', 'closed', 'deactivated', 'emailchanged', 'failedactivation', 'new' ) COLLATE ascii_general_ci NOT NULL default 'new',\n\t\t\tMODIFY user_unsubscribe_key CHAR(32) COLLATE ascii_general_ci NOT NULL default '' COMMENT 'A specific key, it is used when a user wants to unsubscribe from a post comments without signing in',\n\t\t\tMODIFY user_gender          char(1) COLLATE ascii_general_ci NULL");
        task_end();
        task_begin('- Converting user fields table...');
        $DB->query("ALTER TABLE T_users__fielddefs\n\t\t\tMODIFY ufdf_type       char(8) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY ufdf_required   enum('hidden','optional','recommended','require') COLLATE ascii_general_ci NOT NULL default 'optional',\n\t\t\tMODIFY ufdf_duplicated enum('forbidden','allowed','list') COLLATE ascii_general_ci NOT NULL default 'allowed'");
        task_end();
        task_begin('- Converting user reports table...');
        $DB->query("ALTER TABLE T_users__reports\n\t\t\tMODIFY urep_status enum( 'fake', 'guidelines', 'harass', 'spam', 'other' ) COLLATE ascii_general_ci");
        task_end();
        task_begin('- Converting locales table...');
        $DB->query("ALTER TABLE T_locales\n\t\t\tMODIFY loc_charset varchar(15) COLLATE ascii_general_ci NOT NULL default 'iso-8859-1',\n\t\t\tMODIFY loc_datefmt varchar(20) COLLATE ascii_general_ci NOT NULL default 'y-m-d',\n\t\t\tMODIFY loc_timefmt varchar(20) COLLATE ascii_general_ci NOT NULL default 'H:i:s'");
        task_end();
        task_begin('- Converting antispam table...');
        $DB->query("ALTER TABLE {$tableprefix}antispam\n\t\t\tMODIFY aspm_source enum( 'local','reported','central' ) COLLATE ascii_general_ci NOT NULL default 'reported'");
        task_end();
        task_begin('- Converting IP ranges table...');
        $DB->query("ALTER TABLE T_antispam__iprange\n\t\t\tMODIFY aipr_status enum( 'trusted', 'suspect', 'blocked' ) COLLATE ascii_general_ci NULL DEFAULT NULL");
        task_end();
        task_begin('- Converting user settings table...');
        $DB->query("ALTER TABLE T_users__usersettings\n\t\t\tMODIFY uset_name VARCHAR( 30 ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting plugins table...');
        $DB->query("ALTER TABLE T_plugins\n\t\t\tMODIFY plug_classname VARCHAR(40) COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY plug_code      VARCHAR(32) COLLATE ascii_general_ci NULL,\n\t\t\tMODIFY plug_version   VARCHAR(42) COLLATE ascii_general_ci NOT NULL default '0',\n\t\t\tMODIFY plug_status    ENUM( 'enabled', 'disabled', 'needs_config', 'broken' ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting plugin settings table...');
        $DB->query("ALTER TABLE T_pluginsettings\n\t\t\tMODIFY pset_name VARCHAR( 30 ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting plugin user settings table...');
        $DB->query("ALTER TABLE T_pluginusersettings\n\t\t\tMODIFY puset_name VARCHAR( 30 ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting plugin events table...');
        $DB->query("ALTER TABLE T_pluginevents\n\t\t\tMODIFY pevt_event VARCHAR(40) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting cron logs table...');
        $DB->query("ALTER TABLE T_cron__log\n\t\t\tMODIFY clog_status enum('started','finished','error','timeout') COLLATE ascii_general_ci not null default 'started'");
        task_end();
        task_begin('- Converting countries table...');
        $DB->query("ALTER TABLE T_regional__country\n\t\t\tMODIFY ctry_code   char(2) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY ctry_status enum( 'trusted', 'suspect', 'blocked' ) COLLATE ascii_general_ci NULL DEFAULT NULL");
        task_end();
        task_begin('- Converting regions table...');
        $DB->query("ALTER TABLE T_regional__region\n\t\t\tMODIFY rgn_code char(6) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting subregions table...');
        $DB->query("ALTER TABLE T_regional__subregion\n\t\t\tMODIFY subrg_code char(6) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting cities table...');
        $DB->query("ALTER TABLE T_regional__city\n\t\t\tMODIFY city_postcode char(12) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting currencies table...');
        $DB->query("ALTER TABLE T_regional__currency\n\t\t\tMODIFY curr_code char(3) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting email logs table...');
        $DB->query("ALTER TABLE T_email__log\n\t\t\tMODIFY emlog_to     VARCHAR(255) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY emlog_result ENUM( 'ok', 'error', 'blocked' ) COLLATE ascii_general_ci NOT NULL DEFAULT 'ok'");
        task_end();
        task_begin('- Converting email returns table...');
        $DB->query("ALTER TABLE T_email__returns\n\t\t\tMODIFY emret_address   VARCHAR(255) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY emret_errtype   CHAR(1) COLLATE ascii_general_ci NOT NULL DEFAULT 'U'");
        task_end();
        task_begin('- Converting email addresses table...');
        $DB->query("ALTER TABLE T_email__address\n\t\t\tMODIFY emadr_address VARCHAR(255) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY emadr_status  ENUM( 'unknown', 'redemption', 'warning', 'suspicious1', 'suspicious2', 'suspicious3', 'prmerror', 'spammer' ) COLLATE ascii_general_ci NOT NULL DEFAULT 'unknown'");
        task_end();
        //	$DB->commit();
        task_end();
        set_upgrade_checkpoint('11260');
    }
    if ($old_db_version < 11270) {
        // part 16.i trunk aka 12th part of "i6"
        // IPv4 mapped IPv6 addresses maximum length is 45 chars: ex. ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:192.168.158.190
        task_begin('Upgrading comments table...');
        $DB->query("ALTER TABLE T_comments\n\t\t\tMODIFY comment_author_IP varchar(45) COLLATE ascii_general_ci NOT NULL default ''");
        task_end();
        task_begin('Upgrading sessions table...');
        $DB->query("ALTER TABLE T_sessions\n\t\t\tMODIFY sess_ipaddress VARCHAR(45) COLLATE ascii_general_ci NOT NULL DEFAULT ''");
        task_end();
        set_upgrade_checkpoint('11270');
    }
    if ($old_db_version < 11280) {
        // part 16.j trunk aka 12th part of "i6"
        task_begin('Upgrading hit logs table...');
        $DB->query("ALTER TABLE T_hitlog\n\t\t\tMODIFY hit_remote_addr VARCHAR(45) COLLATE ascii_general_ci DEFAULT NULL");
        task_end();
        task_begin('Upgrading blogs table...');
        db_drop_col('T_blogs', 'blog_UID');
        task_end();
        set_upgrade_checkpoint('11280');
    }
    if ($old_db_version < 11285) {
        // part 16.k trunk aka 13th part of "i6"
        task_begin('Updating plugins table...');
        $DB->query('UPDATE T_plugins SET
			plug_code = CASE
				WHEN plug_classname = "generic_ping_plugin"         THEN "b2evGPing"
				WHEN plug_classname = "basic_antispam_plugin"       THEN "b2evBAspm"
				WHEN plug_classname = "flowplayer_plugin"           THEN "b2evFlwP"
				WHEN plug_classname = "html5_mediaelementjs_plugin" THEN "b2evH5MP"
				WHEN plug_classname = "html5_videojs_plugin"        THEN "b2evH5VJSP"
				ELSE plug_code
			END');
        task_end();
        set_upgrade_checkpoint('11285');
    }
    if ($old_db_version < 11286) {
        // part 16.l trunk aka 14th part of "i6"
        task_begin('Upgrade timestamp fields... ');
        $DB->query('ALTER TABLE T_email__log
			MODIFY emlog_timestamp TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_email__returns
			MODIFY emret_timestamp TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_items__prerendering
			MODIFY itpr_datemodified TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_comments__prerendering
			MODIFY cmpr_datemodified TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_users__reports
			MODIFY urep_datetime datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_items__version
			MODIFY iver_edit_datetime datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_messaging__thread
			MODIFY thrd_datemodified datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_messaging__message
			MODIFY msg_datetime datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_messaging__contact
			MODIFY mct_last_contact_datetime datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        task_end();
        set_upgrade_checkpoint('11286');
    }
    if ($old_db_version < 11300) {
        // part 17 trunk aka "i7"
        task_begin('Upgrading locales table...');
        db_add_col('T_locales', 'loc_shorttimefmt', 'varchar(20) COLLATE ascii_general_ci NOT NULL default "H:i" AFTER loc_timefmt');
        task_end();
        task_begin('Creating message prerendering cache table... ');
        $DB->query('CREATE TABLE T_messaging__prerendering(
				mspr_msg_ID              INT(11) UNSIGNED NOT NULL,
				mspr_format              ENUM("htmlbody","entityencoded","xml","text") COLLATE ascii_general_ci NOT NULL,
				mspr_renderers           TEXT NOT NULL,
				mspr_content_prerendered MEDIUMTEXT NULL,
				mspr_datemodified        TIMESTAMP NOT NULL,
				PRIMARY KEY (mspr_msg_ID, mspr_format)
			) ENGINE = innodb');
        db_add_col('T_messaging__message', 'msg_renderers', 'TEXT NOT NULL');
        $DB->query('UPDATE T_messaging__message SET msg_renderers = "default"');
        task_end();
        task_begin('Upgrading categories table...');
        db_add_col('T_categories', 'cat_last_touched_ts', "TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00'");
        $DB->query('UPDATE T_categories SET cat_last_touched_ts = (
			SELECT post_last_touched_ts
			  FROM T_items__item
			       INNER JOIN T_postcats ON postcat_post_ID = post_ID
			 WHERE postcat_cat_ID = cat_ID
			 ORDER BY post_last_touched_ts DESC
			 LIMIT 1 )');
        task_end();
        task_begin('Create table for User post read status... ');
        $DB->query('CREATE TABLE T_users__postreadstatus (
			uprs_user_ID int(11) unsigned NOT NULL,
			uprs_post_ID int(11) unsigned NOT NULL,
			uprs_read_post_ts TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\',
			uprs_read_comment_ts TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\',
			PRIMARY KEY ( uprs_user_ID, uprs_post_ID )
			) ENGINE = innodb');
        task_end();
        task_begin('Create table for System log... ');
        $DB->query("CREATE TABLE T_syslog (\n\t\t\tslg_ID        INT NOT NULL AUTO_INCREMENT,\n\t\t\tslg_timestamp TIMESTAMP NOT NULL,\n\t\t\tslg_origin    ENUM('core', 'plugin') COLLATE ascii_general_ci,\n\t\t\tslg_origin_ID INT UNSIGNED NULL,\n\t\t\tslg_object    ENUM('comment', 'item', 'user') COLLATE ascii_general_ci,\n\t\t\tslg_object_ID INT UNSIGNED NOT NULL,\n\t\t\tslg_message   VARCHAR(255) NOT NULL,\n\t\t\tPRIMARY KEY   (slg_ID),\n\t\t\tINDEX         slg_object (slg_object, slg_object_ID)\n\t\t\t) ENGINE = myisam");
        task_end();
        set_upgrade_checkpoint('11300');
    }
    if ($old_db_version < 11310) {
        // part 18 trunk aka second part of "i7"
        task_begin('Upgrading cron tasks table...');
        load_funcs('cron/_cron.funcs.php');
        $DB->begin();
        $DB->query('ALTER TABLE T_cron__task
			CHANGE COLUMN ctsk_controller ctsk_key varchar(50) COLLATE ascii_general_ci NOT NULL AFTER ctsk_repeat_after,
			CHANGE COLUMN ctsk_name ctsk_name varchar(255) null COMMENT "Specific name of this task. This value is set only if this job name was modified by an admin user"');
        // Update keys from controllers
        // Important: Cron job sql query result must be converted to ascii charset since the ctsk_key is already ascii( ascii_bin collation )
        $DB->query('UPDATE T_cron__task
			INNER JOIN ( ' . cron_job_sql_query('key,ctrl') . ' ) AS temp
			       ON ctsk_key = CONVERT( temp.task_ctrl USING ascii )
			SET ctsk_key = temp.task_key');
        // Reset names to NULL if its are default
        $DB->query($sql = 'UPDATE T_cron__task
			INNER JOIN ( ' . cron_job_sql_query() . ' ) AS temp
			        ON ctsk_key = CONVERT( temp.task_key USING ascii ) AND ctsk_name = CONVERT( temp.task_name USING ' . $DB->connection_charset . ' )
			SET ctsk_name = NULL');
        $DB->commit();
        task_end();
        task_begin('Upgrade table system log... ');
        $DB->query('ALTER TABLE T_syslog
			CHANGE COLUMN slg_object slg_object ENUM(\'comment\', \'item\', \'user\', \'file\') COLLATE ascii_general_ci,
			CHANGE COLUMN slg_object_ID slg_object_ID INT UNSIGNED NULL,
			ADD    COLUMN slg_user_ID INT UNSIGNED NULL AFTER slg_timestamp,
			ADD    COLUMN slg_type ENUM(\'info\', \'warning\', \'error\', \'critical_error\') COLLATE ascii_general_ci NOT NULL DEFAULT \'info\' AFTER slg_user_ID');
        task_end();
        task_begin('Upgrade groups table... ');
        db_add_col('T_groups', 'grp_level', 'int unsigned DEFAULT 0 NOT NULL AFTER grp_name');
        $default_groups_levels = array('Administrators' => 10, 'Moderators' => 8, 'Trusted Users' => 6, 'Normal Users' => 4, 'Misbehaving/Suspect Users' => 2, 'Spammers/Restricted Users' => 1);
        // Build sql query to update group level depending on name
        $group_level_query = 'SELECT group_name, group_level FROM (';
        $first_task = true;
        foreach ($default_groups_levels as $def_group_name => $def_group_level) {
            if ($first_task) {
                $group_level_query .= 'SELECT ' . $DB->quote($def_group_name) . ' AS group_name, ' . $DB->quote($def_group_level) . ' AS group_level';
                $first_task = false;
            } else {
                $group_level_query .= ' UNION SELECT ' . $DB->quote($def_group_name) . ', ' . $DB->quote($def_group_level);
            }
        }
        $group_level_query .= ') AS inner_temp';
        // Set default levels depending on name
        $DB->query('UPDATE T_groups
			INNER JOIN ( ' . $group_level_query . ' ) AS temp
			       ON grp_name = CONVERT( temp.group_name USING ' . $DB->connection_charset . ' )
			  SET grp_level = temp.group_level');
        // Set default '4' level for all other groups
        $DB->query('UPDATE T_groups
			  SET grp_level = 4
			WHERE grp_level = 0');
        // Set default user permissions for Moderators group
        $DB->query('UPDATE T_groups__groupsettings
			  SET gset_value = "moderate"
			WHERE gset_name = "perm_users"
			  AND gset_grp_ID = (SELECT grp_ID FROM T_groups WHERE grp_name = "Moderators")');
        task_end();
        task_begin('Updating general settings...');
        $DB->query('UPDATE T_settings
				SET set_value = ' . $DB->quote('yes') . '
			WHERE set_name = ' . $DB->quote('newusers_canregister') . '
				AND set_value = ' . $DB->quote('1'));
        task_end();
        task_begin('Creating table for User invitation codes... ');
        $DB->query('CREATE TABLE T_users__invitation_code (
			ivc_ID        int(11) unsigned NOT NULL auto_increment,
			ivc_code      varchar(32) COLLATE ascii_general_ci NOT NULL,
			ivc_expire_ts TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\',
			ivc_source    varchar(30) NULL,
			ivc_grp_ID    int(4) NOT NULL,
			PRIMARY KEY ( ivc_ID ),
			UNIQUE ivc_code ( ivc_code )
		) ENGINE = innodb');
        task_end();
        task_begin('Creating table for User organizations... ');
        $DB->query('CREATE TABLE T_users__organization (
			org_ID   INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
			org_name VARCHAR(255) NOT NULL,
			org_url  VARCHAR(2000) NULL,
			PRIMARY KEY ( org_ID ),
			UNIQUE org_name ( org_name )
		) ENGINE = innodb');
        task_end();
        task_begin('Creating table for relations users with organizations... ');
        $DB->query('CREATE TABLE T_users__user_org (
			uorg_user_ID  INT(11) UNSIGNED NOT NULL,
			uorg_org_ID   INT(11) UNSIGNED NOT NULL,
			uorg_accepted TINYINT(1) DEFAULT 0,
			PRIMARY KEY ( uorg_user_ID, uorg_org_ID )
		) ENGINE = innodb');
        task_end();
        // Rename item settings:
        //   "post_custom_headers" to "metakeywords"
        //   "post_metadesc" to "metadesc"
        //   "post_expiry_delay" to "comment_expiry_delay"
        task_begin('Upgrading Item Settings...');
        $DB->query('UPDATE T_items__item_settings
				  SET iset_name = "metakeywords"
				WHERE iset_name = "post_custom_headers"');
        $DB->query('UPDATE T_items__item_settings
				  SET iset_name = "metadesc"
				WHERE iset_name = "post_metadesc"');
        $DB->query('UPDATE T_items__item_settings
				  SET iset_name = "comment_expiry_delay"
				WHERE iset_name = "post_expiry_delay"');
        task_end();
        task_begin('Upgrade table files... ');
        db_add_col('T_files', 'file_type', "enum('image', 'audio', 'other') COLLATE ascii_general_ci NULL DEFAULT NULL AFTER file_ID");
        task_end();
        task_begin('Upgrade table posts... ');
        $DB->query('ALTER TABLE T_items__item
			CHANGE post_title     post_title     VARCHAR(255) NOT NULL,
			CHANGE post_renderers post_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL');
        task_end();
        task_begin('Upgrade table post prerendering cache... ');
        $DB->query('ALTER TABLE T_items__prerendering
			CHANGE itpr_renderers itpr_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL');
        task_end();
        task_begin('Upgrade table post versions... ');
        $DB->query('ALTER TABLE T_items__version
			CHANGE iver_title iver_title VARCHAR(255) NULL');
        task_end();
        task_begin('Upgrade table comments... ');
        $DB->query('ALTER TABLE T_comments
			CHANGE comment_renderers comment_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL');
        task_end();
        task_begin('Upgrade table comment prerendering cache... ');
        $DB->query('ALTER TABLE T_comments__prerendering
			CHANGE cmpr_renderers cmpr_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL');
        task_end();
        task_begin('Upgrade table messages... ');
        $DB->query('ALTER TABLE T_messaging__message
			CHANGE msg_renderers msg_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL');
        task_end();
        task_begin('Upgrade table message prerendering cache... ');
        $DB->query('ALTER TABLE T_messaging__prerendering
			CHANGE mspr_renderers mspr_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL');
        task_end();
        task_begin('Upgrade table user field definitions... ');
        $DB->query('ALTER TABLE T_users__fielddefs
			CHANGE ufdf_options ufdf_options VARCHAR(255) NULL DEFAULT NULL');
        // Change emtpy ufdf_options to NULL, since it must/may be defined only in case of the list ufdf_type
        $DB->query('UPDATE T_users__fielddefs
			SET ufdf_options = NULL
			WHERE ufdf_options = "" AND ufdf_type != "list"');
        task_end();
        task_begin('Upgrade table cron tasks... ');
        $DB->query('ALTER TABLE T_cron__task
			CHANGE ctsk_params ctsk_params varchar(255)');
        task_end();
        task_begin('Upgrading users table...');
        db_add_col('T_users', 'user_salt', 'CHAR(8) NOT NULL default "" AFTER user_pass');
        task_end();
        task_begin('Updating users pass storage...');
        $DB->query('ALTER TABLE T_users MODIFY COLUMN user_pass VARBINARY(32)');
        $DB->query('UPDATE T_users SET user_pass = UNHEX( user_pass )');
        $DB->query('ALTER TABLE T_users MODIFY COLUMN user_pass BINARY(16) NOT NULL');
        task_end();
        set_upgrade_checkpoint('11310');
    }
    if ($old_db_version < 11320) {
        // part 18.a trunk aka third part of "i7"
        task_begin('Update locales to utf-8 charset...');
        db_drop_col('T_locales', 'loc_charset');
        $DB->query('UPDATE T_locales
			SET loc_name = REPLACE( loc_name, "latin1", "utf8" )
			WHERE loc_locale IN ( "en-US", "en-AU", "en-CA", "en-GB", "en-IL", "en-NZ", "en-SG" )');
        $DB->query('UPDATE T_users SET user_locale = "en-US" WHERE user_locale = "en-US-utf8"');
        $DB->query('UPDATE T_blogs SET blog_locale = "en-US" WHERE blog_locale = "en-US-utf8"');
        $DB->query('UPDATE T_items__item SET post_locale = "en-US" WHERE post_locale = "en-US-utf8"');
        $DB->query('UPDATE T_settings SET set_value = "en-US" WHERE set_name = "default_locale" AND set_value = "en-US-utf8"');
        // Check if the 'en-US-utf8' locale is enabled
        $en_us_utf8_enabled = $DB->get_var('SELECT loc_enabled FROM T_locales WHERE loc_locale = "en-US-utf8"');
        if ($en_us_utf8_enabled !== NULL) {
            // The 'en-US-utf8' was enabled we must enable the 'en-US' even if it was not enabled before because we merged the two locales into one
            $en_us_enabled = $DB->get_var('SELECT loc_enabled FROM T_locales WHERE loc_locale = "en-US"');
            if ($en_us_enabled === NULL) {
                // Update "en-US-utf8" to "en-US"
                $DB->query('UPDATE T_locales SET loc_locale = "en-US" WHERE loc_locale = "en-US-utf8"');
            } elseif ($en_us_utf8_enabled && !$en_us_enabled) {
                // Enable the "en-US" locale because it was not enabled but the "en-US-utf8" was
                $DB->query('UPDATE T_locales SET loc_enabled = 1 WHERE loc_locale = "en-US"');
            }
            if ($en_us_enabled !== NULL) {
                // Remove the "en-US-utf8" locale if the "en_US" locale is already in the database
                $DB->query('DELETE FROM T_locales WHERE loc_locale = "en-US-utf8"');
            }
        }
        task_end();
        task_begin('Upgrade table files... ');
        db_add_col('T_files', 'file_can_be_main_profile', 'TINYINT(1) NOT NULL DEFAULT 1');
        task_end();
        task_begin('Add new video file types... ');
        $video_types = array('webm' => "( 'webm', 'WebM video file', 'video/webm', 'file_video', 'browser', 'registered' )", 'ogv' => "( 'ogv', 'Ogg video file', 'video/ogg', 'file_video', 'browser', 'registered' )", 'm3u8' => "( 'm3u8', 'M3U8 video file', 'application/x-mpegurl', 'file_video', 'browser', 'registered' )");
        $SQL = new SQL();
        $SQL->SELECT('ftyp_extensions');
        $SQL->FROM('T_filetypes');
        $SQL->WHERE('ftyp_extensions LIKE "%' . implode('%" OR ftyp_extensions LIKE "%', array_keys($video_types)) . '%"');
        $existing_video_types = $DB->get_col($SQL->get());
        if (!empty($existing_video_types)) {
            // Some video types arleady exist in DB, Exclude them from inserting
            foreach ($existing_video_types as $vtype) {
                unset($video_types[$vtype]);
            }
        }
        if (count($video_types)) {
            // Insert new video file types
            $DB->query("INSERT INTO T_filetypes\n\t\t\t\t( ftyp_extensions, ftyp_name, ftyp_mimetype, ftyp_icon, ftyp_viewtype, ftyp_allowed )\n\t\t\t\tVALUES " . implode(', ', $video_types));
        }
        task_end();
        set_upgrade_checkpoint('11320');
    }
    if ($old_db_version < 11330) {
        // part 18.b trunk aka 4th part of "i7"
        task_begin('Upgrade table blogs... ');
        $DB->query('UPDATE T_blogs
			  SET blog_in_bloglist = "1"
			WHERE blog_in_bloglist > 0');
        $DB->query('ALTER TABLE T_blogs
			CHANGE blog_in_bloglist blog_in_bloglist ENUM( "public", "logged", "member", "never" ) COLLATE ascii_general_ci DEFAULT "public" NOT NULL');
        $DB->query('UPDATE T_blogs
			  SET blog_in_bloglist = "never"
			WHERE blog_in_bloglist = ""');
        task_end();
        set_upgrade_checkpoint('11330');
    }
    if ($old_db_version < 11340) {
        // part 18.c trunk aka 5th part of "i7"
        task_begin('Upgrading blogs table...');
        $DB->query("ALTER TABLE T_blogs\n\t\t\tMODIFY blog_type ENUM( 'main', 'std', 'photo', 'group', 'forum', 'manual' ) COLLATE ascii_general_ci DEFAULT 'std' NOT NULL");
        task_end();
        set_upgrade_checkpoint('11340');
    }
    if ($old_db_version < 11350) {
        // part 18.d trunk aka 6th part of "i7"
        task_begin('Update category ordering...');
        $DB->query('REPLACE INTO T_coll_settings( cset_coll_ID, cset_name, cset_value )
				SELECT blog_ID, "category_ordering", IFNULL( set_value, "alpha" )
				FROM T_blogs LEFT JOIN T_settings ON set_name = "chapter_ordering"');
        $DB->query('DELETE FROM T_settings WHERE set_name = "chapter_ordering"');
        db_add_col('T_categories', 'cat_subcat_ordering', "enum('parent', 'alpha', 'manual') COLLATE ascii_general_ci NULL DEFAULT NULL AFTER cat_order");
        task_end();
        set_upgrade_checkpoint('11350');
    }
    if ($old_db_version < 11360) {
        // part 18.e trunk aka 7th part of "i7"
        task_begin('Upgrade table posts... ');
        $DB->query('ALTER TABLE T_items__item
            CHANGE post_ptyp_ID post_ityp_ID int(10) unsigned NOT NULL DEFAULT 1');
        $DB->query('ALTER TABLE T_items__item
            DROP INDEX post_ptyp_ID');
        $DB->query('ALTER TABLE T_items__item
            ADD INDEX post_ityp_ID ( post_ityp_ID )');
        task_end();
        task_begin('Upgrade table post types... ');
        $DB->query("ALTER TABLE T_items__type\n\t\t\tCHANGE ptyp_ID   ityp_ID   INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,\n\t\t\tCHANGE ptyp_name ityp_name VARCHAR(30) NOT NULL,\n\t\t\tADD ityp_description       TEXT NULL DEFAULT NULL,\n\t\t\tADD ityp_backoffice_tab    VARCHAR(30) NULL DEFAULT NULL,\n\t\t\tADD ityp_template_name     VARCHAR(40) NULL DEFAULT NULL,\n\t\t\tADD ityp_use_title         ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'required',\n\t\t\tADD ityp_use_url           ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tADD ityp_use_text          ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tADD ityp_allow_html        TINYINT DEFAULT 1,\n\t\t\tADD ityp_allow_attachments TINYINT DEFAULT 1,\n\t\t\tADD ityp_use_excerpt       ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tADD ityp_use_title_tag     ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tADD ityp_use_meta_desc     ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tADD ityp_use_meta_keywds   ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tADD ityp_use_tags          ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tADD ityp_allow_featured    TINYINT DEFAULT 1,\n\t\t\tADD ityp_use_country       ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tADD ityp_use_region        ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tADD ityp_use_sub_region    ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tADD ityp_use_city          ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tADD ityp_use_coordinates   ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tADD ityp_use_custom_fields TINYINT DEFAULT 1,\n\t\t\tADD ityp_use_comments      TINYINT DEFAULT 1,\n\t\t\tADD ityp_allow_closing_comments   TINYINT DEFAULT 1,\n\t\t\tADD ityp_allow_disabling_comments TINYINT DEFAULT 0,\n\t\t\tADD ityp_use_comment_expiration   ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional'");
        $DB->query('UPDATE T_items__type SET
			ityp_backoffice_tab = CASE
				WHEN ityp_ID = 1    THEN "Posts"
				WHEN ityp_ID = 1000 THEN "Pages"
				WHEN ityp_ID >= 1400 AND ityp_ID <= 1600 THEN "Intros"
				WHEN ityp_ID = 2000 THEN "Podcasts"
				WHEN ityp_ID = 3000 THEN "Sidebar links"
				WHEN ityp_ID = 4000 THEN "Advertisement"
				WHEN ityp_ID = 5000 THEN NULL
				ELSE "Posts"
			END,
			ityp_template_name = CASE
				WHEN ityp_ID = 1 OR ityp_ID = 2000 THEN "single"
				WHEN ityp_ID = 1000 THEN "page"
				ELSE NULL
			END');
        task_end();
        task_begin('Adding new post types...');
        $DB->begin();
        $new_item_types = array('manual' => array('type_ID' => 100, 'title' => 'Manual Page'), 'forum' => array('type_ID' => 200, 'title' => 'Forum Topic'));
        $item_types_insert_data = array();
        foreach ($new_item_types as $blog_type => $item_type_data) {
            $item_type_ID = $new_item_types[$blog_type]['type_ID'];
            while ($item_type_ID !== NULL) {
                // Find first free post type ID starting with 100
                $free_item_type_ID = $item_type_ID;
                $item_type_ID = $DB->get_var('SELECT ityp_ID FROM T_items__type WHERE ityp_ID = ' . $DB->quote($item_type_ID));
                if ($item_type_ID === NULL) {
                    // Use this free ID for new type
                    $item_types_insert_data[] = '( ' . $free_item_type_ID . ', ' . $DB->quote($new_item_types[$blog_type]['title']) . ', "Posts", "single", 0 )';
                    $new_item_types[$blog_type]['new_type_ID'] = $free_item_type_ID;
                    break;
                }
                $item_type_ID++;
            }
        }
        if (count($item_types_insert_data)) {
            // Insert new post types
            $DB->query('INSERT INTO T_items__type ( ityp_ID, ityp_name, ityp_backoffice_tab, ityp_template_name, ityp_allow_html )
						VALUES ' . implode(', ', $item_types_insert_data));
            // Update types of all post with "Post" type to new created (only for blogs with type 'forum' and 'manual')
            foreach ($new_item_types as $blog_type => $item_type_data) {
                $DB->query('UPDATE T_items__item
					INNER JOIN T_categories
					   ON post_main_cat_ID = cat_ID
					  AND post_ityp_ID = 1
					INNER JOIN T_blogs
					   ON cat_blog_ID = blog_ID
					  AND blog_type = ' . $DB->quote($blog_type) . '
					  SET post_ityp_ID = ' . $DB->quote($item_type_data['new_type_ID']));
            }
        }
        $DB->commit();
        task_end();
        task_begin('Upgrade table comments... ');
        $DB->query("ALTER TABLE T_comments\n\t\t\tCHANGE comment_type comment_type enum('comment','linkback','trackback','pingback','meta') COLLATE ascii_general_ci NOT NULL default 'comment'");
        task_end();
        task_begin('Creating table for custom fields of Post Types... ');
        $DB->query('CREATE TABLE T_items__type_custom_field (
			itcf_ID      INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
			itcf_ityp_ID INT(11) UNSIGNED NOT NULL,
			itcf_label   VARCHAR(255) NOT NULL,
			itcf_name    VARCHAR(255) COLLATE ascii_general_ci NOT NULL,
			itcf_type    ENUM( \'double\', \'varchar\' ) COLLATE ascii_general_ci NOT NULL,
			itcf_order   INT NULL,
			PRIMARY KEY ( itcf_ID ),
			UNIQUE itcf_ityp_ID_name( itcf_ityp_ID, itcf_name )
		) ENGINE = innodb');
        global $posttypes_perms;
        // Create post types for each blog that has at aleast one custom field
        $SQL = new SQL();
        $SQL->SELECT('*');
        $SQL->FROM('T_coll_settings');
        $SQL->WHERE('cset_name LIKE ' . $DB->quote('custom_%'));
        $SQL->ORDER_BY('cset_coll_ID');
        $setting_rows = $DB->get_results($SQL->get());
        $custom_fields = array();
        $blog_setting_delete_data = array();
        $blog_setting_item_types = array();
        if (count($setting_rows)) {
            // Initialize an array of custom fields from blog settings
            foreach ($setting_rows as $setting_row) {
                if (preg_match('/custom_(double|varchar)\\d+/', $setting_row->cset_name, $matches)) {
                    // It is a custom field
                    if (!isset($custom_fields[$setting_row->cset_coll_ID])) {
                        $custom_fields[$setting_row->cset_coll_ID] = array();
                    }
                    // Delete this blog setting
                    $blog_setting_delete_data[] = 'cset_coll_ID = ' . $DB->quote($setting_row->cset_coll_ID) . ' AND cset_name = ' . $DB->quote($setting_row->cset_name);
                    $cf_type = $matches[1];
                    $cf_key = $setting_row->cset_value;
                    $cf_label = '';
                    $cf_name = '';
                    foreach ($setting_rows as $s_row) {
                        if ($s_row->cset_name == 'custom_' . $cf_type . '_' . $cf_key) {
                            // Label
                            $cf_label = $s_row->cset_value;
                            // Delete this blog setting
                            $blog_setting_delete_data[] = 'cset_coll_ID = ' . $DB->quote($s_row->cset_coll_ID) . ' AND cset_name = ' . $DB->quote($s_row->cset_name);
                        }
                        if ($s_row->cset_name == 'custom_fname_' . $cf_key) {
                            // Name
                            $cf_name = $s_row->cset_value;
                            // Delete this blog setting
                            $blog_setting_delete_data[] = 'cset_coll_ID = ' . $DB->quote($s_row->cset_coll_ID) . ' AND cset_name = ' . $DB->quote($s_row->cset_name);
                        }
                    }
                    $custom_fields[$setting_row->cset_coll_ID][] = array('type' => $cf_type, 'key' => $cf_key, 'label' => $cf_label, 'name' => $cf_name);
                }
            }
            if (count($custom_fields)) {
                // Create post type for each blog with custom fields
                $BlogCache =& get_BlogCache();
                $itypes_insert_data = array();
                $item_type_max_ID = $DB->get_var('SELECT MAX( ityp_ID ) FROM T_items__type') + 1;
                foreach ($custom_fields as $blog_ID => $c_fields) {
                    if (!($cf_Blog = $BlogCache->get_by_ID($blog_ID, false, false))) {
                        // Skip incorrect blog ID
                        continue;
                    }
                    $itypes_insert_data[] = '( ' . $item_type_max_ID . ', ' . $DB->quote('custom_' . $cf_Blog->get('shortname')) . ', ' . '"Posts", ' . '"single", ' . $DB->quote($cf_Blog->get_setting('require_title') == 'none' ? 'never' : $cf_Blog->get_setting('require_title')) . ', ' . $DB->quote(intval($cf_Blog->get_setting('allow_html_post'))) . ', ' . $DB->quote($cf_Blog->get_setting('location_country') == 'hidden' ? 'never' : $cf_Blog->get_setting('location_country')) . ', ' . $DB->quote($cf_Blog->get_setting('location_region') == 'hidden' ? 'never' : $cf_Blog->get_setting('location_region')) . ', ' . $DB->quote($cf_Blog->get_setting('location_subregion') == 'hidden' ? 'never' : $cf_Blog->get_setting('location_subregion')) . ', ' . $DB->quote($cf_Blog->get_setting('location_city') == 'hidden' ? 'never' : $cf_Blog->get_setting('location_city')) . ', ' . $DB->quote($cf_Blog->get_setting('show_location_coordinates') ? 'optional' : 'never') . ', ' . $DB->quote(intval($cf_Blog->get_setting('disable_comments_bypost'))) . ' )';
                    // Update default post type
                    $blog_setting_item_types[$cf_Blog->ID] = $item_type_max_ID;
                    $blog_categories = $DB->get_col('SELECT cat_ID FROM T_categories WHERE cat_blog_ID = ' . $cf_Blog->ID);
                    if (count($blog_categories)) {
                        // Set new post type for each post
                        $DB->query('UPDATE T_items__item SET post_ityp_ID = ' . $item_type_max_ID . '
							WHERE post_ityp_ID = 1
							  AND post_main_cat_ID IN ( ' . implode(', ', $blog_categories) . ' )');
                        if (!empty($posttypes_perms['page'])) {
                            // Find the Pages that have at least one defined custom field:
                            $pages_SQL = new SQL();
                            $pages_SQL->SELECT('post_ID');
                            $pages_SQL->FROM('T_items__item');
                            $pages_SQL->FROM_add('INNER JOIN T_items__item_settings ON post_ID = iset_item_ID');
                            $pages_SQL->WHERE('post_main_cat_ID IN ( ' . implode(', ', $blog_categories) . ' )');
                            $pages_SQL->WHERE_and('post_ityp_ID IN ( ' . implode(', ', $posttypes_perms['page']) . ' )');
                            $pages_SQL->WHERE_and('iset_name LIKE ' . $DB->quote('custom_double_%') . ' OR iset_name LIKE ' . $DB->quote('custom_varchar_%'));
                            $pages_SQL->WHERE_and('iset_value != ""');
                            $pages_SQL->GROUP_BY('post_ID');
                            $pages_IDs = $DB->get_col($pages_SQL->get());
                            $page_type_max_ID = 0;
                            if (count($pages_IDs) > 0) {
                                // We have the Pages that have the defined custom fields
                                // Increase post type ID for new special post type for pages
                                $page_type_max_ID = $item_type_max_ID + 1;
                                $itypes_insert_data[] = '( ' . $page_type_max_ID . ', ' . $DB->quote('page_' . $cf_Blog->get('shortname')) . ', ' . '"Pages", ' . '"page", ' . $DB->quote($cf_Blog->get_setting('require_title') == 'none' ? 'never' : $cf_Blog->get_setting('require_title')) . ', ' . $DB->quote(intval($cf_Blog->get_setting('allow_html_post'))) . ', ' . $DB->quote($cf_Blog->get_setting('location_country') == 'hidden' ? 'never' : $cf_Blog->get_setting('location_country')) . ', ' . $DB->quote($cf_Blog->get_setting('location_region') == 'hidden' ? 'never' : $cf_Blog->get_setting('location_region')) . ', ' . $DB->quote($cf_Blog->get_setting('location_subregion') == 'hidden' ? 'never' : $cf_Blog->get_setting('location_subregion')) . ', ' . $DB->quote($cf_Blog->get_setting('location_city') == 'hidden' ? 'never' : $cf_Blog->get_setting('location_city')) . ', ' . $DB->quote($cf_Blog->get_setting('show_location_coordinates') ? 'optional' : 'never') . ', ' . $DB->quote(intval($cf_Blog->get_setting('disable_comments_bypost'))) . ' )';
                                foreach ($c_fields as $c_field) {
                                    // Insert custom field to get new ID
                                    $DB->query('INSERT INTO T_items__type_custom_field ( itcf_ityp_ID, itcf_label, itcf_name, itcf_type )
										VALUES ( ' . $page_type_max_ID . ', ' . $DB->quote($c_field['label']) . ', ' . $DB->quote($c_field['name']) . ', ' . $DB->quote($c_field['type']) . ' )');
                                    $itcf_ID = $DB->insert_id;
                                    // Change the UID of the item settings to the new inserted itcf_ID (ID of the custom field)
                                    $DB->query('UPDATE T_items__item_settings
											SET iset_name = ' . $DB->quote('custom_' . $c_field['type'] . '_' . $itcf_ID) . '
										WHERE iset_item_ID IN ( ' . implode(', ', $pages_IDs) . ' )
											AND iset_name = ' . $DB->quote('custom_' . $c_field['type'] . '_' . $c_field['key']));
                                }
                                // Set new post type for each page
                                $DB->query('UPDATE T_items__item SET post_ityp_ID = ' . $page_type_max_ID . '
									WHERE post_ID IN ( ' . implode(', ', $pages_IDs) . ' )');
                            }
                        }
                    }
                    // Insert custom fields for standard posts (not pages)
                    foreach ($c_fields as $c_field) {
                        // Insert custom field to get new ID
                        $DB->query('INSERT INTO T_items__type_custom_field ( itcf_ityp_ID, itcf_label, itcf_name, itcf_type )
							VALUES ( ' . $item_type_max_ID . ', ' . $DB->quote($c_field['label']) . ', ' . $DB->quote($c_field['name']) . ', ' . $DB->quote($c_field['type']) . ' )');
                        $itcf_ID = $DB->insert_id;
                        // Change the UID of the item settings to the new inserted itcf_ID (ID of the custom field)
                        $DB->query('UPDATE T_items__item_settings
								SET iset_name = ' . $DB->quote('custom_' . $c_field['type'] . '_' . $itcf_ID) . '
							WHERE iset_name = ' . $DB->quote('custom_' . $c_field['type'] . '_' . $c_field['key']));
                    }
                    // Increase post type ID for next
                    $item_type_max_ID += $page_type_max_ID > 0 ? 2 : 1;
                }
                // Insert post types
                $DB->query('INSERT INTO T_items__type ( ityp_ID, ityp_name, ityp_backoffice_tab, ityp_template_name, ityp_use_title, ityp_allow_html, ityp_use_country, ityp_use_region, ityp_use_sub_region, ityp_use_city, ityp_use_coordinates, ityp_allow_disabling_comments )
					VALUES ' . implode(', ', $itypes_insert_data));
                // Delete old blog settings from DB (custom fields)
                $blog_setting_delete_data[] = 'cset_name LIKE "count_custom_%"';
                $DB->query('DELETE FROM T_coll_settings
					WHERE ( ' . implode(') OR (', $blog_setting_delete_data) . ' )');
            }
        }
        // Update default post types
        $blogs = $DB->get_col('SELECT blog_ID FROM T_blogs');
        $sql_update_blog_settings = array();
        foreach ($blogs as $blog_ID) {
            if (isset($blog_setting_item_types[$blog_ID])) {
                // Set it from custom post type
                $current_item_type = $blog_setting_item_types[$blog_ID];
            } else {
                // Set it from first non reserved post type
                if (!isset($first_item_type)) {
                    $reserved_types = array();
                    foreach ($posttypes_perms as $r_types) {
                        $reserved_types = array_merge($reserved_types, $r_types);
                    }
                    $SQL = new SQL();
                    $SQL->SELECT('ityp_ID');
                    $SQL->FROM('T_items__type');
                    if (!empty($reserved_types)) {
                        $SQL->WHERE('ityp_ID NOT IN ( ' . implode(', ', $reserved_types) . ' )');
                    }
                    $SQL->ORDER_BY('ityp_ID');
                    $SQL->LIMIT('1');
                    $first_item_type = $DB->get_var($SQL->get());
                }
                $current_item_type = $first_item_type;
            }
            $sql_update_blog_settings[] = '( ' . $DB->quote($blog_ID) . ', "default_post_type", ' . $DB->quote($current_item_type) . ' )';
        }
        if (!empty($sql_update_blog_settings)) {
            // Execute a query to update the blog settings
            $DB->query('REPLACE INTO T_coll_settings ( cset_coll_ID, cset_name, cset_value )
				VALUES ' . implode(', ', $sql_update_blog_settings));
        }
        task_end();
        task_begin('Updating site settings... ');
        if ($DB->get_var('SELECT set_value FROM T_settings WHERE set_name = "site_color"') === NULL) {
            // Set default site color only when it is not defined yet
            $DB->query('INSERT INTO T_settings ( set_name, set_value )' . ' VALUES ( "site_color", "#ff8c0f" )');
        }
        task_end();
        set_upgrade_checkpoint('11360');
    }
    if ($old_db_version < 11370) {
        // part 18.f trunk aka 8th part of "i7"
        task_begin('Updating user settings... ');
        $DB->query('DELETE FROM T_users__usersettings WHERE uset_name = "admin_skin"');
        task_end();
        set_upgrade_checkpoint('11370');
    }
    if ($old_db_version < 11375) {
        // part 18.g trunk aka 9th part of "i7"
        task_begin('Upgrade table user field definitions... ');
        $DB->query('ALTER TABLE T_users__fielddefs
			ADD ufdf_icon_name varchar(100) COLLATE ascii_general_ci NULL');
        $DB->query('UPDATE T_users__fielddefs SET
			ufdf_icon_name = CASE
				WHEN ufdf_name = "Yahoo IM"      THEN "fa fa-yahoo"
				WHEN ufdf_name = "Skype"         THEN "fa fa-skype"
				WHEN ufdf_name = "Main phone"    THEN "fa fa-phone"
				WHEN ufdf_name = "Cell phone"    THEN "fa fa-mobile-phone"
				WHEN ufdf_name = "Office phone"  THEN "fa fa-phone"
				WHEN ufdf_name = "Home phone"    THEN "fa fa-phone"
				WHEN ufdf_name = "Office FAX"    THEN "fa fa-fax"
				WHEN ufdf_name = "Home FAX"      THEN "fa fa-fax"
				WHEN ufdf_name = "Linkedin"      THEN "fa fa-linkedin fa-x-linkedin--nudge"
				WHEN ufdf_name = "Twitter"       THEN "fa fa-twitter"
				WHEN ufdf_name = "Facebook"      THEN "fa fa-facebook"
				WHEN ufdf_name = "Flickr"        THEN "fa fa-flickr"
				WHEN ufdf_name = "YouTube"       THEN "fa fa-youtube"
				WHEN ufdf_name = "Digg"          THEN "fa fa-digg"
				WHEN ufdf_name = "StumbleUpon"   THEN "fa fa-stumbleupon"
				WHEN ufdf_name = "GitHub"        THEN "fa fa-github-alt"
				WHEN ufdf_name = "Google Plus"   THEN "fa fa-google-plus fa-x-google-plus--nudge"
				WHEN ufdf_name = "Pinterest"     THEN "fa fa-pinterest-p"
				WHEN ufdf_name = "Main address"  THEN "fa fa-building"
				WHEN ufdf_name = "Home address"  THEN "fa fa-home"
				WHEN ufdf_name = "About me"      THEN "fa fa-info-circle"
				WHEN ufdf_name = "I like"        THEN "fa fa-thumbs-o-up"
				WHEN ufdf_name = "I don\'t like" THEN "fa fa-thumbs-o-down"
				ELSE ufdf_icon_name
			END');
        task_end();
        set_upgrade_checkpoint('11375');
    }
    if ($old_db_version < 11380) {
        // part 18.h trunk aka 10th part of "i7"
        task_begin('Update links table... ');
        $DB->query('UPDATE T_links
			  SET link_position = "cover"
			WHERE link_position = "albumart"');
        task_end();
        set_upgrade_checkpoint('11380');
    }
    if ($old_db_version < 11390) {
        // part 18.i trunk aka 11th part of "i7"
        task_begin('Upgrading table of relations users with organizations... ');
        $DB->query('ALTER TABLE T_users__user_org
			ADD COLUMN uorg_role VARCHAR(255) NULL');
        task_end();
        set_upgrade_checkpoint('11390');
    }
    if ($old_db_version < 11400) {
        // part 18.j trunk aka 12th part of "i7"
        task_begin('Upgrade table user field definitions... ');
        $DB->query('ALTER TABLE T_users__fielddefs
			ADD ufdf_code varchar(20) COLLATE ascii_general_ci NULL');
        $update_user_fields = array('Micro bio' => 'microbio', 'I like' => 'ilike', 'I don\'t like' => 'idontlike', 'MSN/Live IM' => 'msnliveim', 'Yahoo IM' => 'yahooim', 'AOL AIM' => 'aolaim', 'ICQ ID' => 'icqid', 'Skype' => 'skype', 'Main phone' => 'mainphone', 'Cell phone' => 'cellphone', 'Office phone' => 'officephone', 'Home phone' => 'homephone', 'Office FAX' => 'officefax', 'Home FAX' => 'homefax', 'Twitter' => 'twitter', 'Facebook' => 'facebook', 'Google Plus' => 'googleplus', 'Linkedin' => 'linkedin', 'GitHub' => 'github', 'Website' => 'website', 'Blog' => 'blog', 'Myspace' => 'myspace', 'Flickr' => 'flickr', 'YouTube' => 'youtube', 'Digg' => 'digg', 'StumbleUpon' => 'stumbleupon', 'Pinterest' => 'pinterest', 'Role' => 'role', 'Organization' => 'organization', 'Division' => 'division', 'VAT ID' => 'vatid', 'Main address' => 'mainaddress', 'Home address' => 'homeaddress');
        foreach ($update_user_fields as $update_user_field_name => $update_user_field_code) {
            $DB->query('UPDATE T_users__fielddefs
				  SET ufdf_code = ' . $DB->quote($update_user_field_code) . '
				WHERE ufdf_name = ' . $DB->quote($update_user_field_name) . '
				LIMIT 1');
            // limit by 1 in order to update only first record to avoid the duplicate codes
        }
        // Update codes for all other unknown fields
        $DB->query('UPDATE T_users__fielddefs
				SET ufdf_code = CONCAT( "code_", ufdf_ID )
			WHERE ufdf_code IS NULL');
        // Make code field unique
        $DB->query('ALTER TABLE T_users__fielddefs
			MODIFY ufdf_code varchar(20) COLLATE ascii_general_ci UNIQUE NOT NULL');
        task_end();
        /*
         * ADD UPGRADES FOR i7 BRANCH __ABOVE__ IN THIS BLOCK.
         *
         * This part will be included in trunk and i7 branches
         */
        set_upgrade_checkpoint('11400');
    }
    if ($old_db_version < 11410) {
        // part 18.k trunk aka 13th part of "i7"
        task_begin('Upgrading skin names... ');
        $DB->query('UPDATE T_skins__skin 
							 SET skin_folder = CASE
									WHEN skin_folder = "bootstrap"        THEN "bootstrap_blog_skin"
									WHEN skin_folder = "bootstrap_main"   THEN "bootstrap_main_skin"
									WHEN skin_folder = "bootstrap_manual" THEN "bootstrap_manual_skin"
									ELSE skin_folder
			END');
        task_end();
        /*
         * ADD UPGRADES FOR i7 BRANCH __ABOVE__ IN THIS BLOCK.
         *
         * This part will be included in trunk and i7 branches
         */
        set_upgrade_checkpoint('11410');
    }
    if ($old_db_version < 11420) {
        // part 18.l trunk aka 14th part of "i7"
        // This upgrade block restores all field collations that may have been broken by the back-office DB convert tool
        // to 'ascii_bin' and 'ascii_general_ci'
        task_begin('Updating hit log keyphrases table...');
        $DB->query('ALTER TABLE T_track__keyphrase
			MODIFY keyp_phrase  VARCHAR( 255 ) COLLATE utf8_bin NOT NULL');
        task_end();
        task_begin('Check and normalize the ASCII charsets/collations... <br />');
        task_begin('- Converting skins table...');
        $DB->query("ALTER TABLE T_skins__skin\n\t\t\tMODIFY skin_type enum('normal','feed','sitemap','mobile','tablet') COLLATE ascii_general_ci NOT NULL default 'normal'");
        task_end();
        task_begin('- Converting blogs table...');
        $DB->query("ALTER TABLE T_blogs\n\t\t\tMODIFY blog_access_type    VARCHAR(10) COLLATE ascii_general_ci NOT NULL DEFAULT 'extrapath',\n\t\t\tMODIFY blog_urlname        VARCHAR(255) COLLATE ascii_general_ci NOT NULL DEFAULT 'urlname',\n\t\t\tMODIFY blog_in_bloglist    ENUM( 'public', 'logged', 'member', 'never' ) COLLATE ascii_general_ci DEFAULT 'public' NOT NULL,\n\t\t\tMODIFY blog_media_location ENUM( 'default', 'subdir', 'custom', 'none' ) COLLATE ascii_general_ci DEFAULT 'default' NOT NULL,\n\t\t\tMODIFY blog_type           ENUM( 'main', 'std', 'photo', 'group', 'forum', 'manual' ) COLLATE ascii_general_ci DEFAULT 'std' NOT NULL");
        task_end();
        task_begin('- Converting blog settings table...');
        $DB->query('ALTER TABLE T_coll_settings
			MODIFY cset_name VARCHAR( 50 ) COLLATE ascii_general_ci NOT NULL');
        task_end();
        task_begin('- Converting widgets table...');
        $DB->query("ALTER TABLE {$tableprefix}widget\n\t\t\tMODIFY wi_type ENUM( 'core', 'plugin' ) COLLATE ascii_general_ci NOT NULL DEFAULT 'core',\n\t\t\tMODIFY wi_code VARCHAR(32) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting categories table...');
        $DB->query("ALTER TABLE T_categories\n\t\t\tMODIFY cat_urlname varchar(255) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY cat_subcat_ordering enum('parent', 'alpha', 'manual') COLLATE ascii_general_ci NULL DEFAULT NULL");
        task_end();
        task_begin('- Converting posts table...');
        $DB->query("ALTER TABLE T_items__item\n\t\t\tMODIFY post_status               enum('published','community','deprecated','protected','private','review','draft','redirected') COLLATE ascii_general_ci NOT NULL default 'published',\n\t\t\tMODIFY post_urltitle             VARCHAR(210) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY post_notifications_status ENUM('noreq','todo','started','finished') COLLATE ascii_general_ci NOT NULL DEFAULT 'noreq',\n\t\t\tMODIFY post_comment_status       ENUM('disabled', 'open', 'closed') COLLATE ascii_general_ci NOT NULL DEFAULT 'open',\n\t\t\tMODIFY post_renderers            VARCHAR(255) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting comments table...');
        $DB->query("ALTER TABLE T_comments\n\t\t\tMODIFY comment_type         enum('comment','linkback','trackback','pingback','meta') COLLATE ascii_general_ci NOT NULL default 'comment',\n\t\t\tMODIFY comment_status       ENUM('published','community','deprecated','protected','private','review','draft','trash') COLLATE ascii_general_ci DEFAULT 'published' NOT NULL,\n\t\t\tMODIFY comment_author_email varchar(255) COLLATE ascii_general_ci NULL,\n\t\t\tMODIFY comment_author_IP    varchar(45) COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY comment_renderers    VARCHAR(255) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY comment_secret       CHAR(32) COLLATE ascii_general_ci NULL default NULL,\n\t\t\tMODIFY comment_notif_status ENUM('noreq','todo','started','finished') COLLATE ascii_general_ci NOT NULL DEFAULT 'noreq' COMMENT 'Have notifications been sent for this comment? How far are we in the process?'");
        task_end();
        task_begin('- Converting post prerendered contents table...');
        $DB->query("ALTER TABLE T_items__prerendering\n\t\t\tMODIFY itpr_format    ENUM('htmlbody','entityencoded','xml','text') COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY itpr_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting comment prerendered contents table...');
        $DB->query("ALTER TABLE T_comments__prerendering\n\t\t\tMODIFY cmpr_format    ENUM('htmlbody','entityencoded','xml','text') COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY cmpr_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting post versions table...');
        $DB->query("ALTER TABLE T_items__version\n\t\t\tMODIFY iver_status ENUM('published','community','deprecated','protected','private','review','draft','redirected') COLLATE ascii_general_ci NULL");
        task_end();
        task_begin('- Converting post types table...');
        $DB->query("ALTER TABLE T_items__type\n\t\t\tMODIFY ityp_use_title              ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'required',\n\t\t\tMODIFY ityp_use_url                ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tMODIFY ityp_use_text               ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tMODIFY ityp_use_excerpt            ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tMODIFY ityp_use_title_tag          ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tMODIFY ityp_use_meta_desc          ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tMODIFY ityp_use_meta_keywds        ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tMODIFY ityp_use_tags               ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional',\n\t\t\tMODIFY ityp_use_country            ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tMODIFY ityp_use_region             ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tMODIFY ityp_use_sub_region         ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tMODIFY ityp_use_city               ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tMODIFY ityp_use_coordinates        ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never',\n\t\t\tMODIFY ityp_use_comment_expiration ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'optional'");
        task_end();
        task_begin('- Converting post types custom fields table...');
        $DB->query("ALTER TABLE T_items__type_custom_field\n\t\t\tMODIFY itcf_name VARCHAR(255) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY itcf_type ENUM( 'double', 'varchar' ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting post settings table...');
        $DB->query("ALTER TABLE T_items__item_settings\n\t\t\tMODIFY iset_name varchar( 50 ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting user permissions table...');
        $DB->query("ALTER TABLE T_coll_user_perms\n\t\t\tMODIFY bloguser_perm_poststatuses set('review','draft','private','protected','deprecated','community','published','redirected') COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY bloguser_perm_edit         ENUM('no','own','lt','le','all','redirected') COLLATE ascii_general_ci NOT NULL default 'no',\n\t\t\tMODIFY bloguser_perm_cmtstatuses  set('review','draft','private','protected','deprecated','community','published') COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY bloguser_perm_edit_cmt     ENUM('no','own','anon','lt','le','all') COLLATE ascii_general_ci NOT NULL default 'no'");
        task_end();
        task_begin('- Converting group permissions table...');
        $DB->query("ALTER TABLE T_coll_group_perms\n\t\t\tMODIFY bloggroup_perm_poststatuses set('review','draft','private','protected','deprecated','community','published','redirected') COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY bloggroup_perm_edit         ENUM('no','own','lt','le','all','redirected') COLLATE ascii_general_ci NOT NULL default 'no',\n\t\t\tMODIFY bloggroup_perm_cmtstatuses  set('review','draft','private','protected','deprecated','community','published') COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY bloggroup_perm_edit_cmt     ENUM('no','own','anon','lt','le','all') COLLATE ascii_general_ci NOT NULL default 'no'");
        task_end();
        task_begin('- Converting links table...');
        $DB->query("ALTER TABLE T_links\n\t\t\tMODIFY link_position varchar(10) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting files table...');
        $DB->query("ALTER TABLE T_files\n\t\t\tMODIFY file_type      enum('image', 'audio', 'other') COLLATE ascii_general_ci NULL DEFAULT NULL,\n\t\t\tMODIFY file_root_type enum('absolute','user','collection','shared','skins','import') COLLATE ascii_general_ci NOT NULL DEFAULT 'absolute'");
        task_end();
        task_begin('- Converting file types table...');
        $DB->query("ALTER TABLE T_filetypes\n\t\t\tMODIFY ftyp_extensions varchar(30) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY ftyp_viewtype   varchar(10) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY ftyp_allowed    enum('any','registered','admin') COLLATE ascii_general_ci NOT NULL default 'admin'");
        task_end();
        task_begin('- Converting messages table...');
        $DB->query("ALTER TABLE T_messaging__message\n\t\t\tMODIFY msg_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting message prerendering contents table...');
        $DB->query("ALTER TABLE T_messaging__prerendering\n\t\t\tMODIFY mspr_format    ENUM('htmlbody','entityencoded','xml','text') COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY mspr_renderers VARCHAR(255) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting sessions table...');
        $DB->query("ALTER TABLE T_sessions\n\t\t\tMODIFY sess_key       CHAR(32) COLLATE ascii_general_ci NULL,\n\t\t\tMODIFY sess_ipaddress VARCHAR(45) COLLATE ascii_general_ci NOT NULL DEFAULT '',\n\t\t\tMODIFY sess_device    VARCHAR(8) COLLATE ascii_general_ci NOT NULL DEFAULT ''");
        task_end();
        task_begin('- Converting domains table...');
        $DB->query("ALTER TABLE T_basedomains\n\t\t\tMODIFY dom_status ENUM('unknown','trusted','suspect','blocked') COLLATE ascii_general_ci NOT NULL DEFAULT 'unknown',\n\t\t\tMODIFY dom_type   ENUM('unknown','normal','searcheng','aggregator','email') COLLATE ascii_general_ci NOT NULL DEFAULT 'unknown'");
        task_end();
        task_begin('- Converting logs table...');
        $DB->query("ALTER TABLE T_hitlog\n\t\t\tMODIFY hit_ctrl         VARCHAR(30) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY hit_type         ENUM('standard','rss','admin','ajax', 'service') COLLATE ascii_general_ci DEFAULT 'standard' NOT NULL,\n\t\t\tMODIFY hit_referer_type ENUM('search','special','spam','referer','direct','self') COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY hit_remote_addr  VARCHAR(45) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY hit_agent_type   ENUM('robot','browser','unknown') COLLATE ascii_general_ci DEFAULT 'unknown' NOT NULL");
        task_end();
        task_begin('- Converting goal categories table...');
        $DB->query("ALTER TABLE T_track__goalcat\n\t\t\tMODIFY gcat_color  char(7) COLLATE ascii_general_ci default NULL");
        task_end();
        task_begin('- Converting groups table...');
        $DB->query("ALTER TABLE T_groups\n\t\t\tMODIFY grp_perm_blogs                  enum('user','viewall','editall') COLLATE ascii_general_ci NOT NULL default 'user',\n\t\t\tMODIFY grp_perm_xhtmlvalidation        VARCHAR(10) COLLATE ascii_general_ci NOT NULL default 'always',\n\t\t\tMODIFY grp_perm_xhtmlvalidation_xmlrpc VARCHAR(10) COLLATE ascii_general_ci NOT NULL default 'always',\n\t\t\tMODIFY grp_perm_stats                  enum('none','user','view','edit') COLLATE ascii_general_ci NOT NULL default 'none'");
        task_end();
        task_begin('- Converting group settings table...');
        $DB->query("ALTER TABLE T_groups__groupsettings\n\t\t\tMODIFY gset_name VARCHAR(30) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting settings table...');
        $DB->query("ALTER TABLE T_settings\n\t\t\tMODIFY set_name VARCHAR(30) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting cache table...');
        $DB->query("ALTER TABLE T_global__cache\n\t\t\tMODIFY cach_name VARCHAR(30) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting users table...');
        $DB->query("ALTER TABLE T_users\n\t\t\tMODIFY user_email           varchar(255) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY user_status          enum( 'activated', 'autoactivated', 'closed', 'deactivated', 'emailchanged', 'failedactivation', 'new' ) COLLATE ascii_general_ci NOT NULL default 'new',\n\t\t\tMODIFY user_unsubscribe_key CHAR(32) COLLATE ascii_general_ci NOT NULL default '' COMMENT 'A specific key, it is used when a user wants to unsubscribe from a post comments without signing in',\n\t\t\tMODIFY user_gender          char(1) COLLATE ascii_general_ci NULL");
        task_end();
        task_begin('- Converting user fields table...');
        $DB->query("ALTER TABLE T_users__fielddefs\n\t\t\tMODIFY ufdf_type       char(8) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY ufdf_required   enum('hidden','optional','recommended','require') COLLATE ascii_general_ci NOT NULL default 'optional',\n\t\t\tMODIFY ufdf_duplicated enum('forbidden','allowed','list') COLLATE ascii_general_ci NOT NULL default 'allowed',\n\t\t\tMODIFY ufdf_icon_name  varchar(100) COLLATE ascii_general_ci NULL,\n\t\t\tMODIFY ufdf_code       varchar(20) COLLATE ascii_general_ci UNIQUE NOT NULL");
        task_end();
        task_begin('- Converting user reports table...');
        $DB->query("ALTER TABLE T_users__reports\n\t\t\tMODIFY urep_status enum( 'fake', 'guidelines', 'harass', 'spam', 'other' ) COLLATE ascii_general_ci");
        task_end();
        task_begin('- Converting user invitation codes table...');
        $DB->query("ALTER TABLE T_users__invitation_code\n\t\t\tMODIFY ivc_code varchar(32) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting locales table...');
        $DB->query("ALTER TABLE T_locales\n\t\t\tMODIFY loc_datefmt varchar(20) COLLATE ascii_general_ci NOT NULL default 'y-m-d',\n\t\t\tMODIFY loc_timefmt varchar(20) COLLATE ascii_general_ci NOT NULL default 'H:i:s',\n\t\t\tMODIFY loc_shorttimefmt varchar(20) COLLATE ascii_general_ci NOT NULL default 'H:i'");
        task_end();
        task_begin('- Converting antispam table...');
        $DB->query("ALTER TABLE {$tableprefix}antispam\n\t\t\tMODIFY aspm_source enum( 'local','reported','central' ) COLLATE ascii_general_ci NOT NULL default 'reported'");
        task_end();
        task_begin('- Converting IP ranges table...');
        $DB->query("ALTER TABLE T_antispam__iprange\n\t\t\tMODIFY aipr_status enum( 'trusted', 'suspect', 'blocked' ) COLLATE ascii_general_ci NULL DEFAULT NULL");
        task_end();
        task_begin('- Converting user settings table...');
        $DB->query("ALTER TABLE T_users__usersettings\n\t\t\tMODIFY uset_name VARCHAR( 30 ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting plugins table...');
        $DB->query("ALTER TABLE T_plugins\n\t\t\tMODIFY plug_classname VARCHAR(40) COLLATE ascii_general_ci NOT NULL default '',\n\t\t\tMODIFY plug_code      VARCHAR(32) COLLATE ascii_general_ci NULL,\n\t\t\tMODIFY plug_version   VARCHAR(42) COLLATE ascii_general_ci NOT NULL default '0',\n\t\t\tMODIFY plug_status    ENUM( 'enabled', 'disabled', 'needs_config', 'broken' ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting plugin settings table...');
        $DB->query("ALTER TABLE T_pluginsettings\n\t\t\tMODIFY pset_name VARCHAR( 30 ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting plugin user settings table...');
        $DB->query("ALTER TABLE T_pluginusersettings\n\t\t\tMODIFY puset_name VARCHAR( 30 ) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting plugin events table...');
        $DB->query("ALTER TABLE T_pluginevents\n\t\t\tMODIFY pevt_event VARCHAR(40) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting cron tasks table...');
        $DB->query("ALTER TABLE T_cron__task\n\t\t\tMODIFY ctsk_key varchar(50) COLLATE ascii_general_ci not null");
        task_end();
        task_begin('- Converting cron logs table...');
        $DB->query("ALTER TABLE T_cron__log\n\t\t\tMODIFY clog_status enum('started','finished','error','timeout') COLLATE ascii_general_ci not null default 'started'");
        task_end();
        task_begin('- Converting countries table...');
        $DB->query("ALTER TABLE T_regional__country\n\t\t\tMODIFY ctry_code   char(2) COLLATE ascii_general_ci NOT NULL,\n\t\t\tMODIFY ctry_status enum( 'trusted', 'suspect', 'blocked' ) COLLATE ascii_general_ci NULL DEFAULT NULL");
        task_end();
        task_begin('- Converting regions table...');
        $DB->query("ALTER TABLE T_regional__region\n\t\t\tMODIFY rgn_code char(6) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting subregions table...');
        $DB->query("ALTER TABLE T_regional__subregion\n\t\t\tMODIFY subrg_code char(6) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting cities table...');
        $DB->query("ALTER TABLE T_regional__city\n\t\t\tMODIFY city_postcode char(12) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting currencies table...');
        $DB->query("ALTER TABLE T_regional__currency\n\t\t\tMODIFY curr_code char(3) COLLATE ascii_general_ci NOT NULL");
        task_end();
        task_begin('- Converting slugs table...');
        $DB->query("ALTER TABLE T_slug\n\t\t\tMODIFY slug_title varchar(255) COLLATE ascii_bin NOT NULL,\n\t\t\tMODIFY slug_type\tchar(6) COLLATE ascii_bin NOT NULL DEFAULT 'item'");
        task_end();
        task_begin('- Converting email logs table...');
        $DB->query("ALTER TABLE T_email__log\n\t\t\tMODIFY emlog_to     VARCHAR(255) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY emlog_result ENUM( 'ok', 'error', 'blocked' ) COLLATE ascii_general_ci NOT NULL DEFAULT 'ok'");
        task_end();
        task_begin('- Converting email returns table...');
        $DB->query("ALTER TABLE T_email__returns\n\t\t\tMODIFY emret_address   VARCHAR(255) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY emret_errtype   CHAR(1) COLLATE ascii_general_ci NOT NULL DEFAULT 'U'");
        task_end();
        task_begin('- Converting email addresses table...');
        $DB->query("ALTER TABLE T_email__address\n\t\t\tMODIFY emadr_address VARCHAR(255) COLLATE ascii_general_ci DEFAULT NULL,\n\t\t\tMODIFY emadr_status  ENUM( 'unknown', 'redemption', 'warning', 'suspicious1', 'suspicious2', 'suspicious3', 'prmerror', 'spammer' ) COLLATE ascii_general_ci NOT NULL DEFAULT 'unknown'");
        task_end();
        task_begin('- Converting system log table...');
        $DB->query("ALTER TABLE T_syslog\n\t\t\tMODIFY slg_type   ENUM('info', 'warning', 'error', 'critical_error') COLLATE ascii_general_ci NOT NULL DEFAULT 'info',\n\t\t\tMODIFY slg_origin ENUM('core', 'plugin') COLLATE ascii_general_ci,\n\t\t\tMODIFY slg_object ENUM('comment', 'item', 'user', 'file') COLLATE ascii_general_ci");
        task_end();
        task_end();
        set_upgrade_checkpoint('11420');
    }
    if ($old_db_version < 11430) {
        // part 18.m trunk aka 15th part of "i7"
        task_begin('Upgrading tags table...');
        // Get all tags that contain not ascii chars, because some mysql versions cannot convert them correctly to utf8_bin
        $not_ascii_tags = $DB->get_results('SELECT *
			 FROM T_items__tag
			WHERE tag_name NOT REGEXP "^[A-Za-z0-9_\\-\\s]+$"');
        foreach ($not_ascii_tags as $not_ascii_tag) {
            // Replace each not ascii char with "_" in tag name in order to avoid error on below table upgrading
            $ascii_tag_name = preg_replace('/[^A-Za-z0-9_\\-\\s]/', '_', $not_ascii_tag->tag_name);
            $ascii_tag_name = str_replace('__', '_', $ascii_tag_name);
            if ($ascii_tag_name == $not_ascii_tag->tag_name) {
                // Skip this tag name because it doesn't contain not ascii chars really
                continue;
            }
            // Check tag name for uniqueness
            $c = 1;
            $new_tag_name = $ascii_tag_name;
            while ($DB->get_var('SELECT tag_ID
				 FROM T_items__tag
				WHERE tag_name = ' . $DB->quote($new_tag_name))) {
                $new_tag_name = $ascii_tag_name . $c;
                $c++;
            }
            // Update tag name to new value without not ascii chars
            $DB->query('UPDATE T_items__tag
				  SET tag_name = ' . $DB->quote($new_tag_name) . '
				WHERE tag_ID = ' . $not_ascii_tag->tag_ID);
        }
        // Remove the empty tags
        $empty_tag_IDs = $DB->get_col('SELECT tag_ID FROM T_items__tag
			WHERE tag_name = ""');
        if (!empty($empty_tag_IDs)) {
            $DB->query('DELETE FROM T_items__tag
				WHERE tag_ID IN ( ' . $DB->quote($empty_tag_IDs) . ' ) ');
            $DB->query('DELETE FROM T_items__itemtag
				WHERE itag_tag_ID IN ( ' . $DB->quote($empty_tag_IDs) . ' ) ');
        }
        // Upgrade field "tag_name" from varbinary to varchar utf8_bin
        $DB->query('ALTER TABLE T_items__tag
			MODIFY tag_name VARCHAR(50) COLLATE utf8_bin NOT NULL');
        // Allow multiple special char variations for each tag
        task_end();
        task_begin('Upgrading collection user/group permissions tables...');
        $DB->query("ALTER TABLE T_coll_user_perms\n\t\t\tMODIFY bloguser_perm_edit ENUM('no','own','lt','le','all') COLLATE ascii_general_ci NOT NULL default 'no'");
        $DB->query("ALTER TABLE T_coll_group_perms\n\t\t\tMODIFY bloggroup_perm_edit ENUM('no','own','lt','le','all') COLLATE ascii_general_ci NOT NULL default 'no'");
        task_end();
        // fp> Note: do NOT put back and "add upgrades" comment here. The comment is OUTSIDE of the block now!
        set_upgrade_checkpoint('11430');
    }
    if ($old_db_version < 11440) {
        // part 18.n trunk aka 16th part of "i7"
        task_begin('Upgrading base domains table...');
        $DB->query("ALTER TABLE T_basedomains\n\t\t\tMODIFY dom_name VARCHAR(250) COLLATE utf8_bin NOT NULL DEFAULT ''");
        task_end();
        set_upgrade_checkpoint('11440');
    }
    if ($old_db_version < 11450) {
        // part 18.o trunk aka 17th part of "i7"
        task_begin('Upgrading blog-group permissions table...');
        $DB->query("ALTER TABLE T_coll_group_perms\n\t\t\tADD COLUMN bloggroup_perm_item_type ENUM('standard','restricted','admin') COLLATE ascii_general_ci NOT NULL default 'standard' AFTER bloggroup_perm_poststatuses,\n\t\t\tDROP COLUMN bloggroup_perm_page,\n\t\t\tDROP COLUMN bloggroup_perm_intro,\n\t\t\tDROP COLUMN bloggroup_perm_podcast,\n\t\t\tDROP COLUMN bloggroup_perm_sidebar");
        task_end();
        task_begin('Upgrading blog-user permissions table...');
        $DB->query("ALTER TABLE T_coll_user_perms\n\t\t\tADD COLUMN bloguser_perm_item_type ENUM('standard','restricted','admin') COLLATE ascii_general_ci NOT NULL default 'standard' AFTER bloguser_perm_poststatuses,\n\t\t\tDROP COLUMN bloguser_perm_page,\n\t\t\tDROP COLUMN bloguser_perm_intro,\n\t\t\tDROP COLUMN bloguser_perm_podcast,\n\t\t\tDROP COLUMN bloguser_perm_sidebar");
        task_end();
        task_begin('Upgrade post types table... ');
        $DB->query("ALTER TABLE T_items__type\n\t\t\tADD COLUMN ityp_perm_level ENUM( 'standard', 'restricted', 'admin' ) COLLATE ascii_general_ci NOT NULL default 'standard'");
        task_end();
        set_upgrade_checkpoint('11450');
    }
    if ($old_db_version < 11460) {
        // part 18.p trunk aka 18th part of "i7"
        task_begin('Creating table for PostType-to-Collection relationships...');
        $DB->query("CREATE TABLE T_items__type_coll (\n\t\t\titc_ityp_ID int(11) unsigned NOT NULL,\n\t\t\titc_coll_ID int(11) unsigned NOT NULL,\n\t\t\tPRIMARY KEY (itc_ityp_ID, itc_coll_ID),\n\t\t\tUNIQUE itemtypecoll ( itc_ityp_ID, itc_coll_ID )\n\t\t) ENGINE = innodb");
        task_end();
        task_begin('Updating collection permissions... ');
        $DB->query('UPDATE T_coll_group_perms
			  SET bloggroup_perm_item_type = "restricted"
			WHERE bloggroup_perm_item_type = "standard"');
        $DB->query('UPDATE T_coll_user_perms
			  SET bloguser_perm_item_type = "restricted"
			WHERE bloguser_perm_item_type = "standard"');
        task_end();
        task_begin('Updating post types table... ');
        $DB->query('UPDATE T_items__type SET
			ityp_perm_level = CASE
				WHEN ityp_ID = "1"    THEN "standard"
				WHEN ityp_ID = "100"  THEN "standard"
				WHEN ityp_ID = "200"  THEN "standard"
				WHEN ityp_ID = "1000" THEN "restricted"
				WHEN ityp_ID = "1400" THEN "restricted"
				WHEN ityp_ID = "1500" THEN "restricted"
				WHEN ityp_ID = "1520" THEN "restricted"
				WHEN ityp_ID = "1530" THEN "restricted"
				WHEN ityp_ID = "1570" THEN "restricted"
				WHEN ityp_ID = "1600" THEN "restricted"
				WHEN ityp_ID = "2000" THEN "standard"
				WHEN ityp_ID = "3000" THEN "admin"
				WHEN ityp_ID = "4000" THEN "admin"
				ELSE ityp_perm_level
			END');
        task_end();
        set_upgrade_checkpoint('11460');
    }
    if ($old_db_version < 11470) {
        // part 18.r trunk aka 19th part of "i7"
        task_begin('Updating widgets table... ');
        // Disable all widgets of Menu container for all "Main" collections
        $DB->query('UPDATE ' . $tableprefix . 'widget
			INNER JOIN T_blogs ON blog_ID = wi_coll_ID AND blog_type = "main"
			  SET wi_enabled = 0
			WHERE wi_sco_name = "Menu"');
        task_end();
        set_upgrade_checkpoint('11470');
    }
    if ($old_db_version < 11480) {
        // part 18.s trunk aka 20th part of "i7"
        task_begin('Updating table for PostType-to-Collection relationships... ');
        // Get all collections:
        $collections_SQL = new SQL();
        $collections_SQL->SELECT('blog_ID, blog_type');
        $collections_SQL->FROM('T_blogs');
        $collections = $DB->get_assoc($collections_SQL->get());
        // Get all post types:
        $posttypes_SQL = new SQL();
        $posttypes_SQL->SELECT('ityp_ID');
        $posttypes_SQL->FROM('T_items__type');
        $posttypes = $DB->get_col($posttypes_SQL->get());
        // Enable post types for the collections:
        $posttypes_collections = array();
        foreach ($collections as $collection_ID => $collection_type) {
            switch ($collection_type) {
                // Set what post types should not be enabled depending on the collection type:
                case 'main':
                case 'photo':
                    $skip_posttypes = array(100, 200, 2000, 5000);
                    break;
                case 'forum':
                    $skip_posttypes = array(1, 100, 2000, 5000);
                    break;
                case 'manual':
                    $skip_posttypes = array(1, 200, 2000, 5000);
                    break;
                default:
                    // 'std'
                    $skip_posttypes = array(100, 200, 5000);
                    break;
            }
            foreach ($posttypes as $posttype_ID) {
                if (in_array($posttype_ID, $skip_posttypes)) {
                    // Skip(Don't enable) this post type for the collection:
                    continue;
                }
                $posttypes_collections[] = '( ' . $posttype_ID . ', ' . $collection_ID . ' )';
            }
        }
        if (count($posttypes_collections)) {
            // Update the relationships only when at least one is required:
            $DB->query('REPLACE INTO T_items__type_coll
				( itc_ityp_ID, itc_coll_ID )
				VALUES ' . implode(', ', $posttypes_collections));
        }
        task_end();
        set_upgrade_checkpoint('11480');
    }
    if ($old_db_version < 11482) {
        // v6.6.3
        task_begin('Updating default post types for forums and manual collections... ');
        $item_types = array('manual' => array('ID' => 100, 'name' => 'Manual Page'), 'forum' => array('ID' => 200, 'name' => 'Forum Topic'));
        $update_default_type_sql = array();
        foreach ($item_types as $collection_type => $item_type) {
            // Try to find an item type by ID or name:
            $item_type_ID = $DB->get_var('SELECT ityp_ID
				 FROM T_items__type
				WHERE ityp_ID = ' . $item_type['ID'] . '
				   OR ityp_name = ' . $DB->quote($item_type['name']));
            if (empty($item_type_ID)) {
                // Item type is not found in DB, Skip it:
                continue;
            }
            // Get all collections with type:
            $type_collection_IDs = $DB->get_col('SELECT blog_ID
				 FROM T_blogs
				WHERE blog_type = ' . $DB->quote($collection_type));
            foreach ($type_collection_IDs as $type_collection_ID) {
                $update_default_type_sql[] = '( ' . $type_collection_ID . ', "default_post_type", ' . $DB->quote($item_type_ID) . ' )';
            }
        }
        if (count($update_default_type_sql) > 0) {
            // Update default post types of collections:
            $DB->query('REPLACE INTO T_coll_settings ( cset_coll_ID, cset_name, cset_value )
				VALUES ' . implode(',', $update_default_type_sql));
        }
        task_end();
        set_upgrade_checkpoint('11482');
    }
    if ($old_db_version < 11483) {
        // v6.6.4
        task_begin('Updating general settings...');
        $DB->query('UPDATE T_settings
				SET set_value = ' . $DB->quote('no') . '
			WHERE set_name = ' . $DB->quote('newusers_canregister') . '
				AND set_value = ' . $DB->quote('0'));
        task_end();
        task_begin('Updating user settings...');
        $DB->query('ALTER TABLE T_users__usersettings CHANGE COLUMN uset_name uset_name VARCHAR( 50 ) COLLATE ascii_general_ci NOT NULL');
        $DB->query('ALTER TABLE T_pluginusersettings CHANGE COLUMN puset_name puset_name VARCHAR( 50 ) COLLATE ascii_general_ci NOT NULL');
        task_end();
        set_upgrade_checkpoint('11483');
    }
    if ($old_db_version < 11484) {
        // part 2 of v6.6.4
        task_begin('Upgrade table item types... ');
        $DB->query("ALTER TABLE T_items__type\n\t\t\tADD ityp_use_parent ENUM( 'required', 'optional', 'never' ) COLLATE ascii_general_ci DEFAULT 'never' AFTER ityp_use_url");
        task_end();
        set_upgrade_checkpoint('11484');
    }
    if ($old_db_version < 11485) {
        // v6.6.6
        task_begin('Upgrade table item types... ');
        $DB->query('ALTER TABLE T_items__type
			ADD ityp_allow_breaks TINYINT DEFAULT 1 AFTER ityp_allow_html');
        $DB->query('UPDATE T_items__type
			SET ityp_allow_breaks = 0,
			    ityp_allow_featured = 0
			WHERE ityp_ID >= 1400
			  AND ityp_ID <= 1600');
        task_end();
        set_upgrade_checkpoint('11485');
    }
    if ($old_db_version < 11486) {
        // part 2 of v6.6.6
        task_begin('Upgrade timestamp fields... ');
        $DB->query('ALTER TABLE T_email__log
			MODIFY emlog_timestamp TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_email__returns
			MODIFY emret_timestamp TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_syslog
			MODIFY slg_timestamp TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_items__prerendering
			MODIFY itpr_datemodified TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_comments__prerendering
			MODIFY cmpr_datemodified TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_messaging__prerendering
			MODIFY mspr_datemodified TIMESTAMP NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_users__reports
			MODIFY urep_datetime datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_items__version
			MODIFY iver_edit_datetime datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_messaging__thread
			MODIFY thrd_datemodified datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_messaging__message
			MODIFY msg_datetime datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        $DB->query('ALTER TABLE T_messaging__contact
			MODIFY mct_last_contact_datetime datetime NOT NULL DEFAULT \'2000-01-01 00:00:00\'');
        task_end();
        // set_upgrade_checkpoint( '11486' );
    }
    /*
     * ADD UPGRADES __ABOVE__ IN A NEW UPGRADE BLOCK.
     *
     * YOU MUST USE:
     * task_begin( 'Descriptive text about action...' );
     * task_end();
     *
     * ALL DB CHANGES MUST BE EXPLICITLY CARRIED OUT. DO NOT RELY ON SCHEMA UPDATES!
     * Schema updates do not survive after several incremental changes.
     *
     * NOTE: every change that gets done here, should bump {@link $new_db_version} (by 100).
     */
    // Execute general upgrade tasks.
    // These tasks needs to be called after every upgrade process, except if they were already executed but the upgrade was not finished because of the max execution time check.
    if (param('exec_general_tasks', 'boolean', 1)) {
        // We haven't executed these general tasks yet:
        // Update modules own b2evo tables
        echo "Calling modules for individual upgrades...<br>\n";
        evo_flush();
        modules_call_method('upgrade_b2evo_tables');
        // Just in case, make sure the db schema version is up to date at the end.
        if ($old_db_version != $new_db_version) {
            // Update DB schema version to $new_db_version
            set_upgrade_checkpoint($new_db_version);
        }
        // We're going to need some environment in order to init caches and create profile picture links...
        if (!is_object($Settings)) {
            // create Settings object
            load_class('settings/model/_generalsettings.class.php', 'GeneralSettings');
            $Settings = new GeneralSettings();
        }
        if (!is_object($Plugins)) {
            // create Plugins object
            load_class('plugins/model/_plugins.class.php', 'Plugins');
            $Plugins = new Plugins();
        }
        // Init Caches:
        load_funcs('tools/model/_system.funcs.php');
        system_init_caches(true, $old_db_version <= 11410);
        // Only force enabling the caches if we upgrade from a version older or equal to 11410 (6.4.2-beta)
        // note: the above outputs messages
        // Check/Repair Caches:
        task_begin('Checking &amp; repairing caches...');
        load_funcs('tools/model/_system.funcs.php');
        // Check all cache folders if exist and work properly. Try to repair cache folders if they aren't ready for operation.
        $check_cache_messages = system_check_caches(true);
        if (is_array($check_cache_messages) && count($check_cache_messages)) {
            // Display errors of the cache checking
            foreach ($check_cache_messages as $check_cache_message) {
                echo '<br /><span class="text-danger"><evo:error>' . $check_cache_message . '</evo:error></span>';
            }
            echo '<br />';
        }
        task_end();
        // Check if profile picture links should be recreated. It won't be executed in each upgrade, but only in those cases when it is required.
        // This requires an up to date database, and also $Plugins and $GeneralSettings objects must be initialized before this.
        // Note: Check $create_profile_picture_links intialization and usage above to get more information.
        if ($create_profile_picture_links) {
            // Create links for all files from the users profile_pictures folder
            task_begin('Creating profile picture links...');
            create_profile_picture_links();
            task_end();
        }
        // Invalidate all page caches after every upgrade.
        // A new version of b2evolution may not use the same links to access special pages.
        // We want to play it safe here so that people don't think that upgrading broke their blog!
        task_begin('Invalidating all page caches to make sure they don\'t contain old action links...');
        invalidate_pagecaches();
        task_end();
        // Reload plugins after every upgrade, to detect even those changes on plugins which didn't require db modifications
        task_begin('Reloading installed plugins to make sure their config is up to date...');
        $Plugins_admin =& get_Plugins_admin();
        $Plugins_admin->reload_plugins();
        task_end();
        // This has to be at the end because plugin install may fail if the DB schema is not current (matching Plugins class).
        // Only new default plugins will be installed, based on $old_db_version.
        // dh> NOTE: if this fails (e.g. fatal error in one of the plugins), it will not get repeated
        task_begin('Installing new default plugins (if any)...');
        install_basic_plugins($old_db_version);
        task_end();
        // Create default cron jobs (this can be done at each upgrade):
        echo "Checking if some default cron jobs need to be installed...<br/>\n";
        evo_flush();
        require_once dirname(__FILE__) . '/_functions_create.php';
        create_default_jobs(true);
        // "Time running low" test: Check if the upgrade script elapsed time is close to the max execution time.
        // Note: This should not really happen except the case when many plugins must be installed.
        task_begin('Checking timing of upgrade...');
        $elapsed_time = time() - $script_start_time;
        $max_exe_time = ini_get('max_execution_time');
        if ($max_exe_time && $elapsed_time > $max_exe_time - 20) {
            // Max exe time not disabled and we're recahing the end
            // URL to continue the upgrade process from install folder
            $recreate_excerpts = $recreate_autogenerated_excerpts ? '&amp;recreate_excerpts=1' : '';
            $upgrade_continue_url = $baseurl . 'install/index.php?locale=' . $locale . '&amp;action=' . $upgrade_action . '&amp;exec_general_tasks=0' . $recreate_excerpts;
            echo 'We are reaching the time limit for this script. Please click <a href="' . $upgrade_continue_url . '">continue</a>...';
            // Dirty temporary solution:
            exit(0);
        }
        task_end();
    }
    if ($recreate_autogenerated_excerpts) {
        if (!is_object($Settings)) {
            // create Settings object
            load_class('settings/model/_generalsettings.class.php', 'GeneralSettings');
            $Settings = new GeneralSettings();
        }
        if (!is_object($Plugins)) {
            // create Plugins object
            load_class('plugins/model/_plugins.class.php', 'Plugins');
            $Plugins = new Plugins();
        }
        task_begin('Recreate autogenerated post excerpts...');
        $upgrade_continue_url = $baseurl . 'install/index.php?locale=' . $locale . '&amp;action=' . $upgrade_action . '&amp;exec_general_tasks=0&amp;recreate_excerpts=1';
        $all_excerpt = param('all_excerpt', 'integer', 0);
        recreate_autogenerated_excerpts($upgrade_continue_url, $all_excerpt == 0);
        task_end();
    }
    // Update the progress bar status
    update_install_progress_bar();
    /*
     * -----------------------------------------------
     * Check to make sure the DB schema is up to date:
     * -----------------------------------------------
     */
    echo "Starting to check DB...<br/>\n";
    evo_flush();
    $upgrade_db_deltas = array();
    // This holds changes to make, if any (just all queries)
    global $debug;
    foreach ($schema_queries as $table => $query_info) {
        // For each table in the schema, check diffs...
        if ($debug) {
            echo '<br />Checking table: ' . $table . ': ';
        }
        $updates = db_delta($query_info[1], array('drop_column', 'drop_index'), false, true);
        if (empty($updates)) {
            if ($debug) {
                echo 'ok';
            }
        } else {
            if ($debug) {
                echo 'NEEDS UPDATE!';
            }
            foreach ($updates as $table => $queries) {
                foreach ($queries as $qinfo) {
                    foreach ($qinfo['queries'] as $query) {
                        // subqueries for this query (usually one, but may include required other queries)
                        $upgrade_db_deltas[] = $query;
                    }
                }
            }
        }
    }
    if ($debug) {
        echo '<br />';
    }
    if (empty($upgrade_db_deltas)) {
        // no upgrades needed:
        echo '<p>' . T_('The database schema is up to date.') . '</p>';
    } else {
        // Upgrades are needed:
        $confirmed_db_upgrade = param('confirmed', 'integer', 0);
        // force confirmation
        $upgrade_db_deltas_confirm_md5 = param('upgrade_db_deltas_confirm_md5', 'string', '');
        if (!$confirmed_db_upgrade) {
            if (!empty($upgrade_db_deltas_confirm_md5)) {
                // received confirmation from form
                if ($upgrade_db_deltas_confirm_md5 != md5(implode('', $upgrade_db_deltas))) {
                    // unlikely to happen
                    echo '<p class="text-danger"><evo:error>' . T_('The DB schema has been changed since confirmation.') . '</evo:error></p>';
                } else {
                    $confirmed_db_upgrade = true;
                }
            }
        }
        if (!$confirmed_db_upgrade) {
            global $action, $form_action;
            load_class('_core/ui/forms/_form.class.php', 'Form');
            if (!empty($form_action)) {
                $Form = new Form($form_action, '', 'post');
            } else {
                $Form = new Form(NULL, '', 'post');
            }
            $Form->begin_form('fform', T_('Upgrade database'));
            $Form->begin_fieldset();
            $Form->hidden('upgrade_db_deltas_confirm_md5', md5(implode('', $upgrade_db_deltas)));
            $Form->hidden('action', $action);
            $Form->hidden('locale', $locale);
            echo '<p>' . T_('The version number is correct, but we have detected changes in the database schema. This can happen if you\'ve been using development versions directly off GitHub...') . '</p>';
            echo '<p>' . T_('The following database changes will be carried out. If you are not sure what this means, it will probably be alright.') . '</p>';
            echo '<ul>';
            foreach ($upgrade_db_deltas as $l_delta) {
                #echo '<li><code>'.nl2br($l_delta).'</code></li>';
                echo '<li><pre>' . str_replace("\t", '  ', $l_delta) . '</pre></li>';
            }
            echo '</ul>';
            $Form->submit(array('', T_('Try to Repair/Upgrade database now!'), 'btn-warning'));
            $Form->end_form();
            return 'need-fix';
        }
        // Alter DB to match DB schema:
        install_make_db_schema_current(true);
    }
    // Force MySQL strict mode
    $DB->query('SET sql_mode = "TRADITIONAL"', 'Force MySQL "strict" mode (and make sure server is not configured with a weird incompatible mode)');
    track_step('upgrade-success');
    return true;
}
Example #2
0
function xmldb_core_upgrade($oldversion = 0)
{
    global $SESSION;
    raise_time_limit(120);
    raise_memory_limit('256M');
    $status = true;
    if ($oldversion < 2009022700) {
        // Get rid of all blocks with position 0 caused by 'about me' block on profile views
        if (count_records('block_instance', 'order', 0) && !count_records_select('block_instance', '"order" < 0')) {
            if (is_mysql()) {
                $ids = get_column_sql('
                    SELECT i.id FROM {block_instance} i
                    INNER JOIN (SELECT view, "column" FROM {block_instance} WHERE "order" = 0) z
                        ON (z.view = i.view AND z.column = i.column)');
                execute_sql('UPDATE {block_instance} SET "order" =  -1 * "order" WHERE id IN (' . join(',', $ids) . ')');
            } else {
                execute_sql('UPDATE {block_instance} SET "order" =  -1 * "order" WHERE id IN (
                    SELECT i.id FROM {block_instance} i
                    INNER JOIN (SELECT view, "column" FROM {block_instance} WHERE "order" = 0) z
                        ON (z.view = i.view AND z.column = i.column))');
            }
            execute_sql('UPDATE {block_instance} SET "order" = 1 WHERE "order" = 0');
            execute_sql('UPDATE {block_instance} SET "order" = -1 * ("order" - 1) WHERE "order" < 0');
        }
    }
    if ($oldversion < 2009031000) {
        reload_html_filters();
    }
    if ($oldversion < 2009031300) {
        $table = new XMLDBTable('institution');
        $expiry = new XMLDBField('expiry');
        $expiry->setAttributes(XMLDB_TYPE_DATETIME);
        add_field($table, $expiry);
        $expirymailsent = new XMLDBField('expirymailsent');
        $expirymailsent->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $expirymailsent);
        $suspended = new XMLDBField('suspended');
        $suspended->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $suspended);
        // Insert a cron job to check for soon expiring and expired institutions
        if (!record_exists('cron', 'callfunction', 'auth_handle_institution_expiries')) {
            $cron = new StdClass();
            $cron->callfunction = 'auth_handle_institution_expiries';
            $cron->minute = '5';
            $cron->hour = '9';
            $cron->day = '*';
            $cron->month = '*';
            $cron->dayofweek = '*';
            insert_record('cron', $cron);
        }
    }
    if ($oldversion < 2009031800) {
        // Files can only attach blogpost artefacts, but we would like to be able to attach them
        // to other stuff.  Rename the existing attachment table artefact_blog_blogpost_file to
        // artefact_file_attachment so we don't end up with many tables doing the same thing.
        execute_sql("ALTER TABLE {artefact_blog_blogpost_file} RENAME TO {artefact_attachment}");
        if (is_postgres()) {
            // Ensure all of the indexes and constraints are renamed
            execute_sql("\n            ALTER TABLE {artefact_attachment} RENAME blogpost TO artefact;\n            ALTER TABLE {artefact_attachment} RENAME file TO attachment;\n\n            ALTER INDEX {arteblogblogfile_blofil_pk} RENAME TO {arteatta_artatt_pk};\n            ALTER INDEX {arteblogblogfile_blo_ix} RENAME TO {arteatta_art_ix};\n            ALTER INDEX {arteblogblogfile_fil_ix} RENAME TO {arteatta_att_ix};\n\n            ALTER TABLE {artefact_attachment} DROP CONSTRAINT {arteblogblogfile_blo_fk};\n            ALTER TABLE {artefact_attachment} ADD CONSTRAINT {arteatta_art_fk} FOREIGN KEY (artefact) REFERENCES {artefact}(id);\n\n            ALTER TABLE {artefact_attachment} DROP CONSTRAINT {arteblogblogfile_fil_fk};\n            ALTER TABLE {artefact_attachment} ADD CONSTRAINT {arteatta_att_fk} FOREIGN KEY (attachment) REFERENCES {artefact}(id);\n            ");
        } else {
            if (is_mysql()) {
                execute_sql("ALTER TABLE {artefact_attachment} DROP FOREIGN KEY {arteblogblogfile_blo_fk}");
                execute_sql("ALTER TABLE {artefact_attachment} DROP INDEX {arteblogblogfile_blo_ix}");
                execute_sql("ALTER TABLE {artefact_attachment} CHANGE blogpost artefact BIGINT(10) DEFAULT NULL");
                execute_sql("ALTER TABLE {artefact_attachment} ADD CONSTRAINT {arteatta_art_fk} FOREIGN KEY {arteatta_art_ix} (artefact) REFERENCES {artefact}(id)");
                execute_sql("ALTER TABLE {artefact_attachment} DROP FOREIGN KEY {arteblogblogfile_fil_fk}");
                execute_sql("ALTER TABLE {artefact_attachment} DROP INDEX {arteblogblogfile_fil_ix}");
                execute_sql("ALTER TABLE {artefact_attachment} CHANGE file attachment BIGINT(10) DEFAULT NULL");
                execute_sql("ALTER TABLE {artefact_attachment} ADD CONSTRAINT {arteatta_att_fk} FOREIGN KEY {arteatta_att_ix} (attachment) REFERENCES {artefact}(id)");
            }
        }
        // Drop the _pending table. From now on files uploaded as attachments will become artefacts
        // straight away.  Hopefully changes to the upload/file browser form will make it clear to
        // the user that these attachments sit in his/her files area as soon as they are uploaded.
        $table = new XMLDBTable('artefact_blog_blogpost_file_pending');
        drop_table($table);
    }
    if ($oldversion < 2009040900) {
        // The view access page has been putting the string 'null' in as a group role in IE.
        set_field('view_access_group', 'role', null, 'role', 'null');
    }
    if ($oldversion < 2009040901) {
        $table = new XMLDBTable('import_installed');
        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('version', XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('release', XMLDB_TYPE_TEXT, 'small', XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('active', XMLDB_TYPE_INTEGER, 1, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 1);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('name'));
        create_table($table);
        $table = new XMLDBTable('import_cron');
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('callfunction', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('minute', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('hour', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('day', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('dayofweek', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('month', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('nextrun', XMLDB_TYPE_DATETIME, null, null);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('plugin', 'callfunction'));
        $table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'import_installed', array('name'));
        create_table($table);
        $table = new XMLDBTable('import_config');
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 100, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('field', XMLDB_TYPE_CHAR, 100, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('value', XMLDB_TYPE_TEXT, 'small', XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('plugin', 'field'));
        $table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'import_installed', array('name'));
        create_table($table);
        $table = new XMLDBTable('import_event_subscription');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('event', XMLDB_TYPE_CHAR, 50, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('callfunction', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'import_installed', array('name'));
        $table->addKeyInfo('eventfk', XMLDB_KEY_FOREIGN, array('event'), 'event_type', array('name'));
        $table->addKeyInfo('subscruk', XMLDB_KEY_UNIQUE, array('plugin', 'event', 'callfunction'));
        create_table($table);
        $table = new XMLDBTable('export_installed');
        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('version', XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('release', XMLDB_TYPE_TEXT, 'small', XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('active', XMLDB_TYPE_INTEGER, 1, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 1);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('name'));
        create_table($table);
        $table = new XMLDBTable('export_cron');
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('callfunction', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('minute', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('hour', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('day', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('dayofweek', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('month', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('nextrun', XMLDB_TYPE_DATETIME, null, null);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('plugin', 'callfunction'));
        $table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'export_installed', array('name'));
        create_table($table);
        $table = new XMLDBTable('export_config');
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 100, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('field', XMLDB_TYPE_CHAR, 100, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('value', XMLDB_TYPE_TEXT, 'small', XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('plugin', 'field'));
        $table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'export_installed', array('name'));
        create_table($table);
        $table = new XMLDBTable('export_event_subscription');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('event', XMLDB_TYPE_CHAR, 50, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('callfunction', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'export_installed', array('name'));
        $table->addKeyInfo('eventfk', XMLDB_KEY_FOREIGN, array('event'), 'event_type', array('name'));
        $table->addKeyInfo('subscruk', XMLDB_KEY_UNIQUE, array('plugin', 'event', 'callfunction'));
        create_table($table);
    }
    if ($oldversion < 2009050700) {
        if ($data = check_upgrades('export.html')) {
            upgrade_plugin($data);
        }
        if ($data = check_upgrades('export.leap')) {
            upgrade_plugin($data);
        }
        if ($data = check_upgrades('import.leap')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2009051200) {
        // Rename submittedto column to submittedgroup
        if (is_postgres()) {
            execute_sql("ALTER TABLE {view} RENAME submittedto TO submittedgroup");
        } else {
            if (is_mysql()) {
                execute_sql("ALTER TABLE {view} DROP FOREIGN KEY {view_sub_fk}");
                execute_sql("ALTER TABLE {view} DROP INDEX {view_sub_ix}");
                execute_sql("ALTER TABLE {view} CHANGE submittedto submittedgroup BIGINT(10) DEFAULT NULL");
                execute_sql("ALTER TABLE {view} ADD CONSTRAINT {view_sub_fk} FOREIGN KEY {view_sub_ix} (submittedgroup) REFERENCES {group}(id)");
            }
        }
        // Add submittedhost column for views submitted to remote moodle hosts
        $table = new XMLDBTable('view');
        $field = new XMLDBField('submittedhost');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, null);
        add_field($table, $field);
        // Do this manually because xmldb tries to create a key with the same name (view_sub_vk) as an existing one, and fails.
        if (is_postgres()) {
            execute_sql("ALTER TABLE {view} ADD CONSTRAINT {view_subh_fk} FOREIGN KEY (submittedhost) REFERENCES {host}(wwwroot)");
            execute_sql("CREATE INDEX {view_subh_ix} ON {view} (submittedhost)");
        } else {
            if (is_mysql()) {
                execute_sql("ALTER TABLE {view} ADD CONSTRAINT {view_subh_fk} FOREIGN KEY {view_subh_ix} (submittedhost) REFERENCES {host}(wwwroot)");
            }
        }
    }
    if ($oldversion < 2009051201) {
        // Invisible view access keys for roaming moodle teachers
        $table = new XMLDBTable('view_access_token');
        $field = new XMLDBField('visible');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
        add_field($table, $field);
    }
    if ($oldversion < 2009052700) {
        // Install a cron job to clean out old exports
        $cron = new StdClass();
        $cron->callfunction = 'export_cleanup_old_exports';
        $cron->minute = '0';
        $cron->hour = '3,13';
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        insert_record('cron', $cron);
    }
    if ($oldversion < 2009070600) {
        // This was forgotten as part of the 1.0 -> 1.1 upgrade
        if ($data = check_upgrades('blocktype.file/html')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2009070700) {
        foreach (array('addfriend', 'removefriend', 'addfriendrequest', 'removefriendrequest') as $eventtype) {
            $event = (object) array('name' => $eventtype);
            ensure_record_exists('event_type', $event, $event);
        }
    }
    if ($oldversion < 2009070900) {
        if (is_mysql()) {
            execute_sql("ALTER TABLE {usr} DROP FOREIGN KEY {usr_las_fk}");
            execute_sql("ALTER TABLE {usr} DROP INDEX {usr_las_ix}");
        }
        $table = new XMLDBTable('usr');
        $field = new XMLDBField('lastauthinstance');
        drop_field($table, $field);
    }
    if ($oldversion < 2009080600) {
        $table = new XMLDBTable('view');
        $index = new XMLDBIndex('view_own_type_uix');
        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('owner'));
        if (!index_exists($table, $index)) {
            // Delete duplicate profile views if there are any, then add an index
            // that will prevent it happening again - but only on postgres, as it's
            // the only db that supports partial indexes
            if ($viewdata = get_records_sql_array("\n                SELECT owner, id\n                FROM {view}\n                WHERE owner IN (\n                    SELECT owner\n                    FROM {view}\n                    WHERE type = 'profile'\n                    GROUP BY owner\n                    HAVING COUNT(*) > 1\n                )\n                AND type = 'profile'\n                ORDER BY owner, id", array())) {
                require_once 'view.php';
                $seen = array();
                foreach ($viewdata as $record) {
                    $seen[$record->owner][] = $record->id;
                }
                foreach ($seen as $owner => $views) {
                    // Remove the first one, which is their real profile view
                    array_shift($views);
                    foreach ($views as $viewid) {
                        delete_records('artefact_feedback', 'view', $viewid);
                        delete_records('view_feedback', 'view', $viewid);
                        delete_records('view_access', 'view', $viewid);
                        delete_records('view_access_group', 'view', $viewid);
                        delete_records('view_access_usr', 'view', $viewid);
                        delete_records('view_access_token', 'view', $viewid);
                        delete_records('view_autocreate_grouptype', 'view', $viewid);
                        delete_records('view_tag', 'view', $viewid);
                        delete_records('usr_watchlist_view', 'view', $viewid);
                        if ($blockinstanceids = get_column('block_instance', 'id', 'view', $viewid)) {
                            foreach ($blockinstanceids as $id) {
                                if (table_exists(new XMLDBTable('blocktype_wall_post'))) {
                                    delete_records('blocktype_wall_post', 'instance', $id);
                                }
                                delete_records('view_artefact', 'block', $id);
                                delete_records('block_instance', 'id', $id);
                            }
                        }
                        delete_records('view', 'id', $viewid);
                    }
                }
            }
            if (is_postgres()) {
                execute_sql("CREATE UNIQUE INDEX {view_own_type_uix} ON {view}(owner) WHERE type = 'profile'");
            }
        }
    }
    if ($oldversion < 2009080601) {
        execute_sql("DELETE FROM {group_member_invite} WHERE \"group\" NOT IN (SELECT id FROM {group} WHERE jointype = 'invite')");
        execute_sql("DELETE FROM {group_member_request} WHERE \"group\" NOT IN (SELECT id FROM {group} WHERE jointype = 'request')");
    }
    if ($oldversion < 2009081800) {
        $event = (object) array('name' => 'creategroup');
        ensure_record_exists('event_type', $event, $event);
    }
    if ($oldversion < 2009082400) {
        $table = new XMLDBTable('usr_registration');
        $field = new XMLDBField('username');
        drop_field($table, $field);
        $field = new XMLDBField('salt');
        drop_field($table, $field);
        $field = new XMLDBField('password');
        drop_field($table, $field);
    }
    if ($oldversion < 2009082600) {
        $captcha = get_config('captcha_on_contact_form');
        set_config('captchaoncontactform', (int) (is_null($captcha) || $captcha));
        $captcha = get_config('captcha_on_register_form');
        set_config('captchaonregisterform', (int) (is_null($captcha) || $captcha));
    }
    if ($oldversion < 2009090700) {
        set_config('showselfsearchsideblock', 1);
        set_config('showtagssideblock', 1);
        set_config('tagssideblockmaxtags', 20);
    }
    if ($oldversion < 2009092100) {
        if ($data = check_upgrades('import.file')) {
            upgrade_plugin($data);
        }
        if ($data = check_upgrades('blocktype.creativecommons')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2009092900) {
        $event = (object) array('name' => 'deleteartefacts');
        ensure_record_exists('event_type', $event, $event);
    }
    if ($oldversion < 2009101600) {
        require_once get_config('docroot') . '/lib/stringparser_bbcode/lib.php';
        // Remove bbcode formatting from existing feedback
        if ($records = get_records_sql_array("SELECT * FROM {view_feedback} WHERE message LIKE '%[%'", array())) {
            foreach ($records as &$r) {
                if (function_exists('parse_bbcode')) {
                    $r->message = parse_bbcode($r->message);
                }
                update_record('view_feedback', $r);
            }
        }
        if ($records = get_records_sql_array("SELECT * FROM {artefact_feedback} WHERE message LIKE '%[%'", array())) {
            foreach ($records as &$r) {
                if (function_exists('parse_bbcode')) {
                    $r->message = parse_bbcode($r->message);
                }
                update_record('artefact_feedback', $r);
            }
        }
    }
    if ($oldversion < 2009102100) {
        // Now the view_layout table has to have records for all column widths
        $record = (object) array('columns' => 1, 'widths' => '100');
        insert_record('view_layout', $record);
        $record = (object) array('columns' => 5, 'widths' => '20,20,20,20,20');
        insert_record('view_layout', $record);
    }
    if ($oldversion < 2009102200) {
        if (!count_records_select('activity_type', 'name = ? AND plugintype IS NULL AND pluginname IS NULL', array('groupmessage'))) {
            insert_record('activity_type', (object) array('name' => 'groupmessage', 'admin' => 0, 'delay' => 0));
        }
    }
    if ($oldversion < 2009102900) {
        $table = new XMLDBTable('usr');
        $field = new XMLDBField('sessionid');
        drop_field($table, $field);
    }
    if ($oldversion < 2009110500) {
        set_config('creategroups', 'all');
    }
    if ($oldversion < 2009110900) {
        // Fix export cronjob so it runs 12 hours apart
        execute_sql("UPDATE {cron} SET hour = '3,15' WHERE callfunction = 'export_cleanup_old_exports'");
        // Cron job to clean old imports
        $cron = new StdClass();
        $cron->callfunction = 'import_cleanup_old_imports';
        $cron->minute = '0';
        $cron->hour = '4,16';
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        insert_record('cron', $cron);
    }
    if ($oldversion < 2009111200) {
        $table = new XMLDBTable('artefact_internal_profile_email');
        $field = new XMLDBField('mailssent');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 2, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
    }
    if ($oldversion < 2009111201) {
        $table = new XMLDBTable('artefact_internal_profile_email');
        $field = new XMLDBField('mailsbounced');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 2, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
    }
    if ($oldversion < 2009120100) {
        // Fix for bug in 1.1 => 1.2 upgrade which may have inserted
        // a second groupmessage activity_type record
        $records = get_records_select_array('activity_type', 'name = ? AND plugintype IS NULL AND pluginname IS NULL', array('groupmessage'), 'id');
        if ($records && count($records) > 1) {
            for ($i = 1; $i < count($records); $i++) {
                delete_records('activity_queue', 'type', $records[$i]->id);
                delete_records('notification_internal_activity', 'type', $records[$i]->id);
                delete_records('notification_emaildigest_queue', 'type', $records[$i]->id);
                delete_records('usr_activity_preference', 'activity', $records[$i]->id);
                delete_records('activity_type', 'id', $records[$i]->id);
            }
        }
    }
    if ($oldversion < 2009120900) {
        $table = new XMLDBTable('view');
        $field = new XMLDBField('theme');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, null);
        add_field($table, $field);
    }
    if ($oldversion < 2010011300) {
        // Clean up the mess left behind by failing to delete blogposts in a transaction
        try {
            include_once get_config('docroot') . 'artefact/lib.php';
            if (function_exists('rebuild_artefact_parent_cache_dirty')) {
                rebuild_artefact_parent_cache_dirty();
            }
        } catch (Exception $e) {
            log_debug('Upgrade 2010011300: rebuild_artefact_parent_cache_dirty failed.');
        }
        execute_sql("\n            INSERT INTO {artefact_blog_blogpost} (blogpost)\n            SELECT id FROM {artefact} WHERE artefacttype = 'blogpost' AND id NOT IN (\n                SELECT blogpost FROM {artefact_blog_blogpost}\n            )");
    }
    if ($oldversion < 2010012701) {
        set_config('userscanchooseviewthemes', 1);
    }
    if ($oldversion < 2010021500) {
        if ($data = check_upgrades('blocktype.recentforumposts')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2010031000) {
        // For existing sites, preserve current user search behaviour:
        // Users are only searchable by their display names.
        set_config('userscanhiderealnames', 1);
        execute_sql("\n            INSERT INTO {usr_account_preference} (usr, field, value)\n            SELECT u.id, 'hiderealname', 1\n            FROM {usr} u LEFT JOIN {usr_account_preference} p ON (u.id = p.usr AND p.field = 'hiderealname')\n            WHERE NOT u.preferredname IS NULL AND u.preferredname != '' AND p.field IS NULL\n        ");
    }
    if ($oldversion < 2010040700) {
        // Set antispam defaults
        set_config('formsecret', get_random_key());
        if (!function_exists('checkdnsrr')) {
            require_once get_config('docroot') . 'lib/antispam.php';
        }
        if (checkdnsrr('test.uribl.com.black.uribl.com', 'A')) {
            set_config('antispam', 'advanced');
        } else {
            set_config('antispam', 'simple');
        }
        set_config('spamhaus', 0);
        set_config('surbl', 0);
    }
    if ($oldversion < 2010040800) {
        $table = new XMLDBTable('view');
        $field = new XMLDBField('submittedtime');
        $field->setAttributes(XMLDB_TYPE_DATETIME, null, null);
        add_field($table, $field);
    }
    if ($oldversion < 2010041200) {
        delete_records('config', 'field', 'captchaoncontactform');
        delete_records('config', 'field', 'captchaonregisterform');
    }
    if ($oldversion < 2010041201) {
        $sql = "\n            SELECT u.id\n            FROM {usr} u\n            LEFT JOIN {artefact} a\n                ON (a.owner = u.id AND a.artefacttype = 'blog')\n            WHERE u.id > 0\n            GROUP BY u.id\n            HAVING COUNT(a.id) != 1";
        $manyblogusers = get_records_sql_array($sql, array());
        if ($manyblogusers) {
            foreach ($manyblogusers as $u) {
                $where = (object) array('usr' => $u->id, 'field' => 'multipleblogs');
                $data = (object) array('usr' => $u->id, 'field' => 'multipleblogs', 'value' => 1);
                ensure_record_exists('usr_account_preference', $where, $data);
            }
        }
    }
    if ($oldversion < 2010041600 && table_exists(new XMLDBTable('view_feedback'))) {
        // Add author, authorname to artefact table
        $table = new XMLDBTable('artefact');
        $field = new XMLDBField('author');
        $field->setAttributes(XMLDB_TYPE_INTEGER, '10');
        add_field($table, $field);
        $key = new XMLDBKey('authorfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('author'), 'usr', array('id'));
        add_key($table, $key);
        table_column('artefact', null, 'authorname', 'text', null, null, null, '');
        if (is_postgres()) {
            execute_sql("ALTER TABLE {artefact} ALTER COLUMN authorname DROP DEFAULT");
            set_field('artefact', 'authorname', null);
            execute_sql('UPDATE {artefact} SET authorname = g.name FROM {group} g WHERE "group" = g.id');
            execute_sql("UPDATE {artefact} SET authorname = CASE WHEN institution = 'mahara' THEN ? ELSE i.displayname END FROM {institution} i WHERE institution = i.name", array(get_config('sitename')));
        } else {
            execute_sql("UPDATE {artefact} a, {group} g SET a.authorname = g.name WHERE a.group = g.id");
            execute_sql("UPDATE {artefact} a, {institution} i SET a.authorname = CASE WHEN a.institution = 'mahara' THEN ? ELSE i.displayname END WHERE a.institution = i.name", array(get_config('sitename')));
        }
        execute_sql('UPDATE {artefact} SET author = owner WHERE owner IS NOT NULL');
        execute_sql('ALTER TABLE {artefact} ADD CHECK (
            (author IS NOT NULL AND authorname IS NULL    ) OR
            (author IS NULL     AND authorname IS NOT NULL)
        )');
        // Move feedback activity type to artefact plugin
        execute_sql("\n            UPDATE {activity_type}\n            SET plugintype = 'artefact', pluginname = 'comment'\n            WHERE name = 'feedback'\n        ");
        // Install the comment artefact
        if ($data = check_upgrades('artefact.comment')) {
            upgrade_plugin($data);
        }
        // Flag all views & artefacts to enable/disable comments
        table_column('artefact', null, 'allowcomments', 'integer', 1);
        table_column('view', null, 'allowcomments', 'integer', 1, null, 1);
        // Initially allow comments on blogposts, images, files
        set_field_select('artefact', 'allowcomments', 1, 'artefacttype IN (?,?,?)', array('blogpost', 'image', 'file'));
        // Convert old feedback to comment artefacts
        if ($viewfeedback = get_records_sql_array('
            SELECT f.*, v.id AS viewid, v.owner, v.group, v.institution
            FROM {view_feedback} f JOIN {view} v ON f.view = v.id', array())) {
            foreach ($viewfeedback as &$f) {
                if ($f->author > 0) {
                    $f->authorname = null;
                } else {
                    $f->author = null;
                    if (empty($f->authorname)) {
                        $f->authorname = '?';
                    }
                }
                $artefact = (object) array('artefacttype' => 'comment', 'owner' => $f->owner, 'group' => $f->group, 'institution' => $f->institution, 'author' => $f->author, 'authorname' => $f->authorname, 'title' => get_string('Comment', 'artefact.comment'), 'description' => $f->message, 'ctime' => $f->ctime, 'atime' => $f->ctime, 'mtime' => $f->ctime);
                $aid = insert_record('artefact', $artefact, 'id', true);
                $comment = (object) array('artefact' => $aid, 'private' => 1 - $f->public, 'onview' => $f->viewid);
                insert_record('artefact_comment_comment', $comment);
                if (!empty($f->attachment)) {
                    insert_record('artefact_attachment', (object) array('artefact' => $aid, 'attachment' => $f->attachment));
                }
            }
        }
        // We are throwing away the view information from artefact_feedback.
        // From now on all artefact comments appear together and are not
        // tied to a particular view.
        if ($artefactfeedback = get_records_sql_array('
            SELECT f.*, a.id AS artefactid, a.owner, a.group, a.institution
            FROM {artefact_feedback} f JOIN {artefact} a ON f.artefact = a.id', array())) {
            foreach ($artefactfeedback as &$f) {
                if ($f->author > 0) {
                    $f->authorname = null;
                } else {
                    $f->author = null;
                    if (empty($f->authorname)) {
                        $f->authorname = '?';
                    }
                }
                $artefact = (object) array('artefacttype' => 'comment', 'owner' => $f->owner, 'group' => $f->group, 'institution' => $f->institution, 'author' => $f->author, 'authorname' => $f->authorname, 'title' => get_string('Comment', 'artefact.comment'), 'description' => $f->message, 'ctime' => $f->ctime, 'atime' => $f->ctime, 'mtime' => $f->ctime);
                $aid = insert_record('artefact', $artefact, 'id', true);
                $comment = (object) array('artefact' => $aid, 'private' => 1 - $f->public, 'onartefact' => $f->artefactid);
                insert_record('artefact_comment_comment', $comment);
            }
        }
        // Drop feedback tables
        $table = new XMLDBTable('view_feedback');
        drop_table($table);
        $table = new XMLDBTable('artefact_feedback');
        drop_table($table);
        // Add site setting for anonymous comments
        set_config('anonymouscomments', 1);
    }
    if ($oldversion < 2010041900 && !table_exists(new XMLDBTable('site_data'))) {
        // Upgrades for admin stats pages
        // Table for collection of historical stats
        $table = new XMLDBTable('site_data');
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, XMLDB_NOTNULL);
        $table->addFieldInfo('type', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('value', XMLDB_TYPE_TEXT, 'small', null);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('ctime', 'type'));
        create_table($table);
        // Insert cron jobs to save site data
        $cron = new StdClass();
        $cron->callfunction = 'cron_site_data_weekly';
        $cron->minute = 55;
        $cron->hour = 23;
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = 6;
        insert_record('cron', $cron);
        $cron = new StdClass();
        $cron->callfunction = 'cron_site_data_daily';
        $cron->minute = 51;
        $cron->hour = 23;
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        insert_record('cron', $cron);
        // Put best guess at installation time into config table.
        set_config('installation_time', get_field_sql("SELECT MIN(ctime) FROM {site_content}"));
        // Save the current time so we know when we started collecting stats
        set_config('stats_installation_time', db_format_timestamp(time()));
        // Add ctime to usr table for daily count of users created
        $table = new XMLDBTable('usr');
        $field = new XMLDBField('ctime');
        $field->setAttributes(XMLDB_TYPE_DATETIME, null, null);
        add_field($table, $field);
        // Add visits column to view table
        $table = new XMLDBTable('view');
        $field = new XMLDBField('visits');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        // Add table to store daily view visits
        $table = new XMLDBTable('view_visit');
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('view', XMLDB_TYPE_INTEGER, 10, false, XMLDB_NOTNULL);
        $table->addKeyInfo('viewfk', XMLDB_KEY_FOREIGN, array('view'), 'view', array('id'));
        $table->addIndexInfo('ctimeix', XMLDB_INDEX_NOTUNIQUE, array('ctime'));
        create_table($table);
        // Insert a cron job to check for new versions of Mahara
        $cron = new StdClass();
        $cron->callfunction = 'cron_check_for_updates';
        $cron->minute = rand(0, 59);
        $cron->hour = rand(0, 23);
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        insert_record('cron', $cron);
    }
    if ($oldversion < 2010042600) {
        // @todo: Move to notification/internal
        $table = new XMLDBTable('notification_internal_activity');
        $field = new XMLDBField('parent');
        $field->setAttributes(XMLDB_TYPE_INTEGER, '10');
        add_field($table, $field);
        $key = new XMLDBKey('parentfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('parent'), 'notification_internal_activity', array('id'));
        add_key($table, $key);
        $field = new XMLDBField('from');
        $field->setAttributes(XMLDB_TYPE_INTEGER, '10');
        add_field($table, $field);
        $key = new XMLDBKey('fromfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('from'), 'usr', array('id'));
        add_key($table, $key);
        // Set from column for old user messages
        $usermessages = get_records_array('notification_internal_activity', 'type', get_field('activity_type', 'id', 'name', 'usermessage'));
        if ($usermessages) {
            foreach ($usermessages as &$m) {
                if (preg_match('/sendmessage\\.php\\?id=(\\d+)/', $m->url, $match)) {
                    set_field('notification_internal_activity', 'from', $match[1], 'id', $m->id);
                }
            }
        }
    }
    if ($oldversion < 2010042602 && !get_record('view_type', 'type', 'dashboard')) {
        insert_record('view_type', (object) array('type' => 'dashboard'));
        if ($data = check_upgrades('blocktype.inbox')) {
            upgrade_plugin($data);
        }
        if ($data = check_upgrades('blocktype.newviews')) {
            upgrade_plugin($data);
        }
        // Install system dashboard view
        require_once get_config('libroot') . 'view.php';
        $dbtime = db_format_timestamp(time());
        $viewdata = (object) array('type' => 'dashboard', 'owner' => 0, 'numcolumns' => 2, 'ownerformat' => FORMAT_NAME_PREFERREDNAME, 'title' => get_string('dashboardviewtitle', 'view'), 'template' => 1, 'ctime' => $dbtime, 'atime' => $dbtime, 'mtime' => $dbtime);
        $id = insert_record('view', $viewdata, 'id', true);
        $accessdata = (object) array('view' => $id, 'accesstype' => 'loggedin');
        insert_record('view_access', $accessdata);
        $blocktypes = array(array('blocktype' => 'newviews', 'title' => get_string('title', 'blocktype.newviews'), 'column' => 1, 'config' => array('limit' => 5)), array('blocktype' => 'myviews', 'title' => get_string('title', 'blocktype.myviews'), 'column' => 1, 'config' => null), array('blocktype' => 'inbox', 'title' => get_string('inboxblocktitle'), 'column' => 2, 'config' => array('feedback' => true, 'groupmessage' => true, 'institutionmessage' => true, 'maharamessage' => true, 'usermessage' => true, 'viewaccess' => true, 'watchlist' => true, 'maxitems' => '5')), array('blocktype' => 'inbox', 'title' => get_string('topicsimfollowing'), 'column' => 2, 'config' => array('newpost' => true, 'maxitems' => '5')));
        $installed = get_column_sql('SELECT name FROM {blocktype_installed}');
        $weights = array(1 => 0, 2 => 0);
        foreach ($blocktypes as $blocktype) {
            if (in_array($blocktype['blocktype'], $installed)) {
                $weights[$blocktype['column']]++;
                insert_record('block_instance', (object) array('blocktype' => $blocktype['blocktype'], 'title' => $blocktype['title'], 'view' => $id, 'column' => $blocktype['column'], 'order' => $weights[$blocktype['column']], 'configdata' => serialize($blocktype['config'])));
            }
        }
    }
    if ($oldversion < 2010042603) {
        execute_sql('ALTER TABLE {usr} ADD COLUMN showhomeinfo SMALLINT NOT NULL DEFAULT 1');
        set_config('homepageinfo', 1);
    }
    if ($oldversion < 2010042604) {
        // @todo: Move to notification/internal
        $table = new XMLDBTable('notification_internal_activity');
        $field = new XMLDBField('urltext');
        $field->setAttributes(XMLDB_TYPE_TEXT);
        add_field($table, $field);
    }
    if ($oldversion < 2010051000) {
        set_field('activity_type', 'delay', 1, 'name', 'groupmessage');
    }
    if ($oldversion < 2010052000) {
        $showusers = get_config('showonlineuserssideblock');
        set_config('showonlineuserssideblock', (int) (is_null($showusers) || $showusers));
    }
    if ($oldversion < 2010060300) {
        // Add table to associate users with php session ids
        $table = new XMLDBTable('usr_session');
        $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, false, XMLDB_NOTNULL);
        $table->addFieldInfo('session', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('session'));
        $table->addIndexInfo('usrix', XMLDB_INDEX_NOTUNIQUE, array('usr'));
        create_table($table);
    }
    if ($oldversion < 2010061100) {
        set_config('registerterms', 1);
    }
    if ($oldversion < 2010061800) {
        insert_record('view_type', (object) array('type' => 'grouphomepage'));
        if ($data = check_upgrades('blocktype.groupmembers')) {
            upgrade_plugin($data);
        }
        if ($data = check_upgrades('blocktype.groupinfo')) {
            upgrade_plugin($data);
        }
        if ($data = check_upgrades('blocktype.groupviews')) {
            upgrade_plugin($data);
        }
        $dbtime = db_format_timestamp(time());
        // create a system template for group homepage views
        require_once get_config('libroot') . 'view.php';
        $viewdata = (object) array('type' => 'grouphomepage', 'owner' => 0, 'numcolumns' => 1, 'template' => 1, 'title' => get_string('grouphomepage', 'view'), 'ctime' => $dbtime, 'atime' => $dbtime, 'mtime' => $dbtime);
        $id = insert_record('view', $viewdata, 'id', true);
        $accessdata = (object) array('view' => $id, 'accesstype' => 'loggedin');
        insert_record('view_access', $accessdata);
        $blocktypes = array(array('blocktype' => 'groupinfo', 'title' => '', 'column' => 1, 'config' => null), array('blocktype' => 'recentforumposts', 'title' => get_string('latestforumposts', 'interaction.forum'), 'column' => 1, 'config' => null), array('blocktype' => 'groupviews', 'title' => get_string('Views', 'view'), 'column' => 1, 'config' => null), array('blocktype' => 'groupmembers', 'title' => get_string('Members', 'group'), 'column' => 1, 'config' => null));
        $installed = get_column_sql('SELECT name FROM {blocktype_installed}');
        foreach ($blocktypes as $k => $blocktype) {
            if (!in_array($blocktype['blocktype'], $installed)) {
                unset($blocktypes[$k]);
            }
        }
        $weights = array(1 => 0);
        foreach ($blocktypes as $blocktype) {
            $weights[$blocktype['column']]++;
            insert_record('block_instance', (object) array('blocktype' => $blocktype['blocktype'], 'title' => $blocktype['title'], 'view' => $id, 'column' => $blocktype['column'], 'order' => $weights[$blocktype['column']], 'configdata' => serialize($blocktype['config'])));
        }
        // add a default group homepage view for all groups in the system
        unset($viewdata->owner);
        $viewdata->template = 0;
        if (!($groups = get_records_array('group', '', '', '', 'id,public'))) {
            $groups = array();
        }
        foreach ($groups as $group) {
            $viewdata->group = $group->id;
            $id = insert_record('view', $viewdata, 'id', true);
            insert_record('view_access', (object) array('view' => $id, 'accesstype' => $group->public ? 'public' : 'loggedin'));
            insert_record('view_access_group', (object) array('view' => $id, 'group' => $group->id));
            $weights = array(1 => 0);
            foreach ($blocktypes as $blocktype) {
                $weights[$blocktype['column']]++;
                insert_record('block_instance', (object) array('blocktype' => $blocktype['blocktype'], 'title' => $blocktype['title'], 'view' => $id, 'column' => $blocktype['column'], 'order' => $weights[$blocktype['column']], 'configdata' => serialize($blocktype['config'])));
            }
        }
    }
    if ($oldversion < 2010062502) {
        //new feature feedback control on views
        $table = new XMLDBTable('view_access');
        $field = new XMLDBField('allowcomments');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        $field = new XMLDBField('approvecomments');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
        add_field($table, $field);
        // Add comment approval to view/artefact (default 0)
        $field = new XMLDBField('approvecomments');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        $table = new XMLDBTable('view');
        add_field($table, $field);
        $table = new XMLDBTable('artefact');
        add_field($table, $field);
        // view_access_(group|usr|token) tables are getting wide with duplicated columns,
        // so just create all the necessary columns in view_access and move stuff there
        $table = new XMLDBTable('view_access');
        $field = new XMLDBField('accesstype');
        $field->setAttributes(XMLDB_TYPE_CHAR, 16, null, null);
        change_field_notnull($table, $field);
        $field = new XMLDBField('group');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, null);
        add_field($table, $field);
        $field = new XMLDBField('role');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null);
        add_field($table, $field);
        $field = new XMLDBField('usr');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, null);
        add_field($table, $field);
        $field = new XMLDBField('token');
        $field->setAttributes(XMLDB_TYPE_CHAR, 100, null, null);
        add_field($table, $field);
        $field = new XMLDBField('visible');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
        add_field($table, $field);
        // Copy data to view_access
        execute_sql('
            INSERT INTO {view_access} (view, accesstype, "group", role, startdate, stopdate)
            SELECT view, NULL, "group", role, startdate, stopdate FROM {view_access_group}');
        execute_sql('
            INSERT INTO {view_access} (view, accesstype, usr, startdate, stopdate)
            SELECT view, NULL, usr, startdate, stopdate FROM {view_access_usr}');
        execute_sql('
            INSERT INTO {view_access} (view, accesstype, token, visible, startdate, stopdate)
            SELECT view, NULL, token, visible, startdate, stopdate FROM {view_access_token}');
        // Add foreign keys
        $key = new XMLDBKey('groupfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('group'), 'group', array('id'));
        add_key($table, $key);
        $key = new XMLDBKey('usrfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
        add_key($table, $key);
        $index = new XMLDBIndex('tokenuk');
        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('token'));
        add_index($table, $index);
        // Exactly one of accesstype, group, usr, token must be not null
        execute_sql('ALTER TABLE {view_access} ADD CHECK (
            (accesstype IS NOT NULL AND "group" IS NULL     AND usr IS NULL     AND token IS NULL) OR
            (accesstype IS NULL     AND "group" IS NOT NULL AND usr IS NULL     AND token IS NULL) OR
            (accesstype IS NULL     AND "group" IS NULL     AND usr IS NOT NULL AND token IS NULL) OR
            (accesstype IS NULL     AND "group" IS NULL     AND usr IS NULL     AND token IS NOT NULL)
        )');
        // Drop old tables
        $table = new XMLDBTable('view_access_group');
        drop_table($table);
        $table = new XMLDBTable('view_access_usr');
        drop_table($table);
        $table = new XMLDBTable('view_access_token');
        drop_table($table);
        // Insert explicit tutor access records for submitted views
        if (!($submittedviews = get_records_sql_array('
            SELECT v.id, v.submittedgroup, g.grouptype
            FROM {view} v JOIN {group} g ON (v.submittedgroup = g.id AND g.deleted = 0)', array()))) {
            $submittedviews = array();
        }
        $roles = array();
        foreach ($submittedviews as $v) {
            if (!isset($roles[$v->grouptype])) {
                $rs = get_column('grouptype_roles', 'role', 'grouptype', $v->grouptype, 'see_submitted_views', 1);
                $roles[$v->grouptype] = empty($rs) ? array() : $rs;
            }
            foreach ($roles[$v->grouptype] as $role) {
                $accessrecord = (object) array('view' => $v->id, 'group' => $v->submittedgroup, 'role' => $role, 'visible' => 0, 'allowcomments' => 1, 'approvecomments' => 0);
                ensure_record_exists('view_access', $accessrecord, $accessrecord);
            }
        }
    }
    if ($oldversion < 2010070700) {
        $table = new XMLDBTable('group_category');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('title', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('displayorder', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        create_table($table);
        $table = new XMLDBTable('group');
        $field = new XMLDBField('category');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10);
        add_field($table, $field);
        $key = new XMLDBKey('categoryfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('category'), 'group_category', array('id'));
        add_key($table, $key);
    }
    if ($oldversion < 2010071300) {
        set_config('searchusernames', 1);
    }
    if ($oldversion < 2010071500) {
        reload_html_filters();
    }
    if ($oldversion < 2010071600) {
        if (is_postgres()) {
            // change_field_enum should do this
            execute_sql('ALTER TABLE {view_access} DROP CONSTRAINT {viewacce_acc_ck}');
        }
        $table = new XMLDBTable('view_access');
        $field = new XMLDBField('accesstype');
        $field->setAttributes(XMLDB_TYPE_CHAR, 16, null, null, null, XMLDB_ENUM, array('public', 'loggedin', 'friends', 'objectionable'));
        change_field_enum($table, $field);
    }
    if ($oldversion < 2010071900) {
        $table = new XMLDBTable('group');
        $field = new XMLDBField('viewnotify');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
        add_field($table, $field);
    }
    if ($oldversion < 2010081000) {
        // new table collection
        $table = new XMLDBTable('collection');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('owner', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('mtime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('description', XMLDB_TYPE_TEXT, null);
        $table->addFieldInfo('navigation', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('usrfk', XMLDB_KEY_FOREIGN, array('owner'), 'usr', array('id'));
        create_table($table);
        // new table collection_view
        $table = new XMLDBTable('collection_view');
        $table->addFieldInfo('view', XMLDB_TYPE_INTEGER, 10, false, XMLDB_NOTNULL);
        $table->addFieldInfo('collection', XMLDB_TYPE_INTEGER, 10, false, XMLDB_NOTNULL);
        $table->addFieldInfo('displayorder', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('view'));
        $table->addKeyInfo('viewfk', XMLDB_KEY_FOREIGN, array('view'), 'view', array('id'));
        $table->addKeyInfo('collectionfk', XMLDB_KEY_FOREIGN, array('collection'), 'collection', array('id'));
        create_table($table);
        // Drop unique constraint on token column of view_access
        $table = new XMLDBTable('view_access');
        $index = new XMLDBIndex('tokenuk');
        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('token'));
        drop_index($table, $index);
        $index = new XMLDBIndex('tokenix');
        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('token'));
        add_index($table, $index);
    }
    if ($oldversion < 2010081001) {
        if ($data = check_upgrades('artefact.plans')) {
            upgrade_plugin($data);
        }
        if ($data = check_upgrades('blocktype.plans/plans')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2010081100) {
        if ($data = check_upgrades('blocktype.navigation')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2010082000) {
        delete_records_select('config', "field IN ('usersrank', 'groupsrank', 'viewsrank')");
    }
    if ($oldversion < 2010091300) {
        // Cron job missing from installs post 2010041900
        if (!record_exists('cron', 'callfunction', 'cron_check_for_updates')) {
            $cron = new StdClass();
            $cron->callfunction = 'cron_check_for_updates';
            $cron->minute = rand(0, 59);
            $cron->hour = rand(0, 23);
            $cron->day = '*';
            $cron->month = '*';
            $cron->dayofweek = '*';
            insert_record('cron', $cron);
        }
    }
    if ($oldversion < 2010091500) {
        // Previous version of 2010040800 upgrade created the submittedtime
        // column not null (see bug #638550)
        $table = new XMLDBTable('view');
        $field = new XMLDBField('submittedtime');
        $field->setAttributes(XMLDB_TYPE_DATETIME, null, null);
        change_field_notnull($table, $field);
        // Our crappy db is full of redundant data (submittedtime depends on
        // submittedhost or submittedgroup) so it's easy to correct this.
        execute_sql("\n            UPDATE {view} SET submittedtime = NULL\n            WHERE submittedtime IS NOT NULL AND submittedgroup IS NULL AND submittedhost IS NULL");
    }
    if ($oldversion < 2010100702) {
        // Add general notification cleanup cron
        if (!record_exists('cron', 'callfunction', 'cron_clean_internal_activity_notifications')) {
            $cron = new StdClass();
            $cron->callfunction = 'cron_clean_internal_activity_notifications';
            $cron->minute = 45;
            $cron->hour = 22;
            $cron->day = '*';
            $cron->month = '*';
            $cron->dayofweek = '*';
            insert_record('cron', $cron);
        }
    }
    if ($oldversion < 2010110800) {
        // Encrypt all passwords with no set salt values
        $sql = "SELECT * FROM {usr}\n                WHERE salt IS NULL OR salt = ''";
        if ($passwords = get_records_sql_array($sql, array())) {
            foreach ($passwords as $p) {
                $p->salt = substr(md5(rand(1000000, 9999999)), 2, 8);
                $p->password = sha1($p->salt . $p->password);
                update_record('usr', $p);
            }
        }
    }
    if ($oldversion < 2010122200) {
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('priority');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 1);
        add_field($table, $field);
        set_field('institution', 'priority', 0, 'name', 'mahara');
    }
    if ($oldversion < 2010122201) {
        $table = new XMLDBTable('view');
        $field = new XMLDBField('accessconf');
        $field->setAttributes(XMLDB_TYPE_CHAR, 40, XMLDB_UNSIGNED, null);
        add_field($table, $field);
    }
    if ($oldversion < 2010122700) {
        $table = new XMLDBTable('view_access');
        $index = new XMLDBIndex('accesstypeix');
        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('accesstype'));
        add_index($table, $index);
    }
    if ($oldversion < 2011012800) {
        reload_html_filters();
    }
    if ($oldversion < 2011032500) {
        // Uninstall solr plugin; it's moving to contrib until it's fixed up.
        delete_records('search_cron', 'plugin', 'solr');
        delete_records('search_event_subscription', 'plugin', 'solr');
        delete_records('search_config', 'plugin', 'solr');
        delete_records('search_installed', 'name', 'solr');
        $searchplugin = get_config('searchplugin');
        if ($searchplugin == 'solr') {
            set_config('searchplugin', 'internal');
        }
    }
    if ($oldversion < 2011041800) {
        // Remove titles from system dashboard, group homepage blocks, so new users/groups
        // get blocks with automatically generated, translatable default titles.
        $systemdashboard = get_field('view', 'id', 'owner', 0, 'type', 'dashboard');
        set_field_select('block_instance', 'title', '', "view = ? AND blocktype IN ('newviews','myviews','inbox')", array($systemdashboard));
        $systemgrouphomepage = get_field('view', 'id', 'owner', 0, 'type', 'grouphomepage');
        set_field_select('block_instance', 'title', '', "view = ? AND blocktype IN ('recentforumposts','groupviews','groupmembers')", array($systemgrouphomepage));
    }
    if ($oldversion < 2011042000) {
        // Create empty variables in database for email configuration
        set_config('smtphosts', '');
        set_config('smtpport', '');
        set_config('smtpuser', '');
        set_config('smtppass', '');
        set_config('smtpsecure', '');
        $SESSION->add_info_msg('Email settings now can be configured via Site settings, however they may be overriden by those set in the config file. If you have no specific reason to use config file email configuration, please consider moving them to Site settings area.');
    }
    if ($oldversion < 2011050300) {
        if (get_config('httpswwwroot')) {
            // Notify users about httpswwwroot removal if it is still set
            $SESSION->add_info_msg('HTTPS logins have been deprecated, you need to remove the httpswwwroot variable from config file and switch your wwwroot to https so that the whole site is served over HTTPS.<br>See <a href="https://bugs.launchpad.net/mahara/+bug/646713">https://bugs.launchpad.net/mahara/+bug/646713</a> for more details.', 0);
        }
    }
    if ($oldversion < 2011050600) {
        $table = new XMLDBTable('usr');
        $field = new XMLDBField('username');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        // This drops the unique index on the username column in postgres.
        // See upgrade 2011051800.
        change_field_precision($table, $field);
    }
    if ($oldversion < 2011051700) {
        // Create new "external" category
        insert_record('blocktype_category', (object) array('name' => 'external'));
        // Migrate existing blocktypes to the new category
        set_field('blocktype_installed_category', 'category', 'external', 'category', 'feeds');
        set_field('blocktype_installed_category', 'category', 'external', 'blocktype', 'externalvideo');
        set_field('blocktype_installed_category', 'category', 'external', 'blocktype', 'googleapps');
        // Delete old "feeds" category
        delete_records('blocktype_category', 'name', 'feeds');
    }
    if ($oldversion < 2011051800) {
        // Restore index that may be missing due to upgrade 2011050600.
        $table = new XMLDBTable('usr');
        $index = new XMLDBIndex('usr_use_uix');
        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('username'));
        if (!index_exists($table, $index)) {
            if (is_postgres()) {
                // For postgres, create the index on the lowercase username, the way it's
                // done in core_postinst().
                execute_sql('CREATE UNIQUE INDEX {usr_use_uix} ON {usr}(LOWER(username))');
            } else {
                $index = new XMLDBIndex('usernameuk');
                $index->setAttributes(XMLDB_INDEX_UNIQUE, array('username'));
                add_index($table, $index);
            }
        }
    }
    if ($oldversion < 2011052300) {
        if ($data = check_upgrades("blocktype.googleapps")) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2011061100) {
        // This block fixes an issue of upgrading from 1.4_STABLE to master
        // version number is date after 1.4_STABLE
        // 2011052400
        // add_field checks if field exists
        $table = new XMLDBTable('view_access');
        $field = new XMLDBField('ctime');
        $field->setAttributes(XMLDB_TYPE_DATETIME, null, null);
        add_field($table, $field);
        // 2011053100
        // add_field checks if field exists
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('defaultquota');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10);
        add_field($table, $field);
        // 2011053101
        // add_field checks if field exists
        $table = new XMLDBTable('group');
        $field = new XMLDBField('quota');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10);
        add_field($table, $field);
        $field = new XMLDBField('quotaused');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        // 2011060700
        // add_field checks if field exists
        $table = new XMLDBTable('view');
        $field = new XMLDBField('retainview');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        // 2011060701
        // site setting to limit online users count
        if (!get_config('onlineuserssideblockmaxusers')) {
            set_config('onlineuserssideblockmaxusers', 10);
        }
        // 2011060701
        // add_field checks if field exists
        // instiutional setting to limit online users type
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('showonlineusers');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 2);
        add_field($table, $field);
    }
    if ($oldversion < 2011061300) {
        // Add more indexes to the usr table for user searches
        if (is_postgres()) {
            $table = new XMLDBTable('usr');
            $index = new XMLDBIndex('usr_fir_ix');
            $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('firstname', 'lastname', 'preferredname', 'studentid', 'email'));
            if (!index_exists($table, $index)) {
                execute_sql('CREATE INDEX {usr_fir_ix} ON {usr}(LOWER(firstname))');
                execute_sql('CREATE INDEX {usr_las_ix} ON {usr}(LOWER(lastname))');
                execute_sql('CREATE INDEX {usr_pre_ix} ON {usr}(LOWER(preferredname))');
                execute_sql('CREATE INDEX {usr_stu_ix} ON {usr}(LOWER(studentid))');
                execute_sql('CREATE INDEX {usr_ema_ix} ON {usr}(LOWER(email))');
            }
        }
    }
    if ($oldversion < 2011061400) {
        // Add institution to group table
        $table = new XMLDBTable('group');
        $field = new XMLDBField('institution');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null);
        add_field($table, $field);
        $key = new XMLDBKey('institutionfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
        add_key($table, $key);
        // Add shortname to group table
        $table = new XMLDBTable('group');
        $field = new XMLDBField('shortname');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null);
        add_field($table, $field);
        $index = new XMLDBIndex('shortnameuk');
        $index->setAttributes(XMLDB_KEY_UNIQUE, array('institution', 'shortname'));
        add_index($table, $index);
    }
    if ($oldversion < 2011061500) {
        // Add favourites
        $table = new XMLDBTable('favorite');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
        $table->addFieldInfo('owner', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('shortname', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('institution', XMLDB_TYPE_CHAR, 255, null, null);
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, XMLDB_NOTNULL);
        $table->addFieldInfo('mtime', XMLDB_TYPE_DATETIME, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('ownerfk', XMLDB_KEY_FOREIGN, array('owner'), 'usr', array('id'));
        $table->addKeyInfo('institutionfk', XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
        $table->addIndexInfo('ownershortuk', XMLDB_INDEX_UNIQUE, array('owner', 'shortname'));
        create_table($table);
        $table = new XMLDBTable('favorite_usr');
        $table->addFieldInfo('favorite', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('favorite,usr'));
        $table->addKeyInfo('favoritefk', XMLDB_KEY_FOREIGN, array('favorite'), 'favorite', array('id'));
        $table->addKeyInfo('usrfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
        create_table($table);
    }
    if ($oldversion < 2011062100) {
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('allowinstitutionpublicviews');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
        add_field($table, $field);
    }
    if ($oldversion < 2011062200) {
        $table = new XMLDBTable('usr_tag');
        $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('tag', XMLDB_TYPE_CHAR, 128, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('usr', 'tag'));
        $table->addKeyInfo('usrfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
        create_table($table);
    }
    if ($oldversion < 2011062300) {
        // Install a cron job to generate the sitemap
        if (!record_exists('cron', 'callfunction', 'cron_sitemap_daily')) {
            $cron = new StdClass();
            $cron->callfunction = 'cron_sitemap_daily';
            $cron->minute = '0';
            $cron->hour = '1';
            $cron->day = '*';
            $cron->month = '*';
            $cron->dayofweek = '*';
            insert_record('cron', $cron);
        }
    }
    if ($oldversion < 2011062400) {
        // self-registration per institution confrimation setting
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('registerconfirm');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
        add_field($table, $field);
        $table = new XMLDBTable('usr_registration');
        $field = new XMLDBField('pending');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        $table = new XMLDBTable('usr_registration');
        $field = new XMLDBField('reason');
        $field->setAttributes(XMLDB_TYPE_TEXT);
        add_field($table, $field);
    }
    if ($oldversion < 2011062700) {
        set_config('dropdownmenu', 0);
    }
    if ($oldversion < 2011070500) {
        // Add profileicon foreign key to artefact table, first clearing any bad profileicon
        // values out of usr.
        execute_sql("\n            UPDATE {usr} SET profileicon = NULL\n            WHERE NOT profileicon IN (SELECT id FROM {artefact} WHERE artefacttype = 'profileicon')");
        $table = new XMLDBTable('usr');
        $key = new XMLDBKey('profileiconfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('profileicon'), 'artefact', array('id'));
        add_key($table, $key);
    }
    if ($oldversion < 2011070501) {
        // Add logo to institution table
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('logo');
        $field->setAttributes(XMLDB_TYPE_INTEGER, '10');
        add_field($table, $field);
        $key = new XMLDBKey('logofk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('logo'), 'artefact', array('id'));
        add_key($table, $key);
    }
    if ($oldversion < 2011072200) {
        if (is_postgres()) {
            execute_sql("\n                UPDATE {group}\n                SET quota = CASE WHEN f.quotaused < 52428800 THEN 52428800 ELSE f.quotaused + 52428800 END,\n                    quotaused = f.quotaused\n                FROM (\n                    SELECT g.id AS id, COALESCE(gf.quotaused, 0) AS quotaused\n                    FROM {group} g\n                        LEFT OUTER JOIN (\n                            SELECT a.group, SUM(aff.size) AS quotaused\n                            FROM {artefact} a JOIN {artefact_file_files} aff ON a.id = aff.artefact\n                            WHERE NOT a.group IS NULL\n                            GROUP BY a.group\n                        ) gf ON gf.group = g.id\n                    WHERE g.quota IS NULL AND g.quotaused = 0 AND g.deleted = 0\n                ) f\n                WHERE {group}.id = f.id");
        } else {
            execute_sql("\n                UPDATE {group}, (\n                    SELECT g.id AS id, COALESCE(gf.quotaused, 0) AS quotaused\n                    FROM {group} g\n                        LEFT OUTER JOIN (\n                            SELECT a.group, SUM(aff.size) AS quotaused\n                            FROM {artefact} a JOIN {artefact_file_files} aff ON a.id = aff.artefact\n                            WHERE NOT a.group IS NULL\n                            GROUP BY a.group\n                        ) gf ON gf.group = g.id\n                    WHERE g.quota IS NULL AND g.quotaused = 0 AND g.deleted = 0\n                ) f\n                SET quota = CASE WHEN f.quotaused < 52428800 THEN 52428800 ELSE f.quotaused + 52428800 END,\n                    {group}.quotaused = f.quotaused\n                WHERE {group}.id = f.id");
        }
    }
    if ($oldversion < 2011072600) {
        // Add tables to store custom institution styles
        // Currently only institutions can use them, but merge this with skin tables later...
        $table = new XMLDBTable('style');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('title', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('css', XMLDB_TYPE_TEXT);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        create_table($table);
        $table = new XMLDBTable('style_property');
        $table->addFieldInfo('style', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('field', XMLDB_TYPE_CHAR, 100, null, XMLDB_NOTNULL);
        $table->addFieldInfo('value', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('style', 'field'));
        $table->addKeyInfo('stylefk', XMLDB_KEY_FOREIGN, array('style'), 'style', array('id'));
        create_table($table);
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('style');
        $field->setAttributes(XMLDB_TYPE_INTEGER, '10');
        add_field($table, $field);
        $key = new XMLDBKey('stylefk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('style'), 'style', array('id'));
        add_key($table, $key);
    }
    if ($oldversion < 2011082200) {
        // Doing a direct insert of the new artefact type instead of running upgrade_plugin(), in order to support the
        // transition from old profile fields to the new socialprofile artefact in Mahara 1.10
        if (!record_exists('artefact_installed_type', 'name', 'html', 'plugin', 'internal')) {
            insert_record('artefact_installed_type', (object) array('name' => 'html', 'plugin' => 'internal'));
        }
        // Move the textbox blocktype into artefact/internal
        set_field('blocktype_installed', 'artefactplugin', 'internal', 'name', 'textbox');
        if ($data = check_upgrades("blocktype.internal/textbox")) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2011082300) {
        // Add institution to view_access table
        $table = new XMLDBTable('view_access');
        $field = new XMLDBField('institution');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null);
        if (!field_exists($table, $field)) {
            add_field($table, $field);
            // Add foreign key
            $key = new XMLDBKey('institutionfk');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
            add_key($table, $key);
            if (is_postgres()) {
                // Update constraint checks
                execute_sql('ALTER TABLE {view_access} DROP CONSTRAINT {view_access_check}');
                execute_sql('ALTER TABLE {view_access} ADD CHECK (
                    (accesstype IS NOT NULL AND "group" IS NULL     AND usr IS NULL     AND token IS NULL     AND institution IS NULL    ) OR
                    (accesstype IS NULL     AND "group" IS NOT NULL AND usr IS NULL     AND token IS NULL     AND institution IS NULL    ) OR
                    (accesstype IS NULL     AND "group" IS NULL     AND usr IS NOT NULL AND token IS NULL     AND institution IS NULL    ) OR
                    (accesstype IS NULL     AND "group" IS NULL     AND usr IS NULL     AND token IS NOT NULL AND institution IS NULL    ) OR
                    (accesstype IS NULL     AND "group" IS NULL     AND usr IS NULL     AND token IS NULL     AND institution IS NOT NULL))');
            } else {
                // MySQL doesn't support these types of constraints
            }
        }
    }
    if ($oldversion < 2011082400) {
        // Add cron entry for cache cleanup
        $cron = new StdClass();
        $cron->callfunction = 'file_cleanup_old_cached_files';
        $cron->minute = '0';
        $cron->hour = '1';
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        insert_record('cron', $cron);
    }
    if ($oldversion < 2011082401) {
        // Set config value for logged-in profile view access
        set_config('loggedinprofileviewaccess', 1);
    }
    if ($oldversion < 2011083000) {
        // Jointype changes
        $table = new XMLDBTable('group');
        $field = new XMLDBField('request');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        set_field('group', 'request', 1, 'jointype', 'request');
        // Turn all request & invite groups into the 'approve' type
        $field = new XMLDBField('jointype');
        $field->setAttributes(XMLDB_TYPE_CHAR, 20, null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('open', 'controlled', 'request', 'invite', 'approve'), 'open');
        if (is_postgres()) {
            execute_sql('ALTER TABLE {group} DROP CONSTRAINT {grou_joi_ck}');
        }
        change_field_enum($table, $field);
        set_field('group', 'jointype', 'approve', 'jointype', 'request');
        set_field('group', 'jointype', 'approve', 'jointype', 'invite');
        $field->setAttributes(XMLDB_TYPE_CHAR, 20, null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('open', 'controlled', 'approve'), 'open');
        if (is_postgres()) {
            execute_sql('ALTER TABLE {group} DROP CONSTRAINT {grou_joi_ck}');
        }
        change_field_enum($table, $field);
        // Move view submission from grouptype to group
        $field = new XMLDBField('submittableto');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        execute_sql("UPDATE {group} SET submittableto = 1 WHERE grouptype IN (SELECT name FROM {grouptype} WHERE submittableto = 1)");
        $table = new XMLDBTable('grouptype');
        $field = new XMLDBField('submittableto');
        drop_field($table, $field);
        // Any group can potentially take submissions, so make sure someone can assess them
        set_field('grouptype_roles', 'see_submitted_views', 1, 'role', 'admin');
        // Move group view editing permission from grouptype_roles to the group table
        $table = new XMLDBTable('group');
        $field = new XMLDBField('editroles');
        $field->setAttributes(XMLDB_TYPE_CHAR, 20, null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('all', 'notmember', 'admin'), 'all');
        add_field($table, $field);
        execute_sql("\n            UPDATE {group} SET editroles = 'notmember' WHERE grouptype IN (\n                SELECT grouptype FROM {grouptype_roles} WHERE role = 'member' AND edit_views = 0\n            )");
        $table = new XMLDBTable('grouptype_roles');
        $field = new XMLDBField('edit_views');
        drop_field($table, $field);
    }
    if ($oldversion < 2011090900) {
        $table = new XMLDBTable('usr');
        $field = new XMLDBField('password');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        change_field_type($table, $field, true, true);
    }
    if ($oldversion < 2011091200) {
        // Locked group views (only editable by group admins)
        $table = new XMLDBTable('view');
        $field = new XMLDBField('locked');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        set_field('view', 'locked', 1, 'type', 'grouphomepage');
        // Setting to hide groups from the "Find Groups" listing
        $table = new XMLDBTable('group');
        $field = new XMLDBField('hidden');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        // Setting to hide group members
        $field = new XMLDBField('hidemembers');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        // Setting to hide group members from members
        $field = new XMLDBField('hidemembersfrommembers');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        // Allow group members to invite friends
        $field = new XMLDBField('invitefriends');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        // Allow group members to recommend the group to friends
        $field = new XMLDBField('suggestfriends');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
    }
    if ($oldversion < 2011091300) {
        $table = new XMLDBTable('blocktype_category');
        $field = new XMLDBField('sort');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 2, XMLDB_UNSIGNED, null);
        add_field($table, $field);
        execute_sql("UPDATE {blocktype_category} SET sort = ? WHERE name = ?", array('0', 'fileimagevideo'));
        execute_sql("UPDATE {blocktype_category} SET sort = ? WHERE name = ?", array('1', 'blog'));
        execute_sql("UPDATE {blocktype_category} SET sort = ? WHERE name = ?", array('2', 'general'));
        execute_sql("UPDATE {blocktype_category} SET sort = ? WHERE name = ?", array('3', 'internal'));
        execute_sql("UPDATE {blocktype_category} SET sort = ? WHERE name = ?", array('4', 'resume'));
        execute_sql("UPDATE {blocktype_category} SET sort = ? WHERE name = ?", array('5', 'external'));
        $index = new XMLDBIndex('sortuk');
        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('sort'));
        add_index($table, $index, false);
    }
    if ($oldversion < 2011092600) {
        // Move the taggedposts blocktype into artefact/blog/blocktype
        set_field('blocktype_installed', 'artefactplugin', 'blog', 'name', 'taggedposts');
    }
    if ($oldversion < 2011102700) {
        $table = new XMLDBTable('usr');
        $field = new XMLDBField('logintries');
        $field->setAttributes(XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        // Every 5 minutes, reset everyone's login attempts to 0
        $cron = new StdClass();
        $cron->callfunction = 'user_login_tries_to_zero';
        $cron->minute = '*/5';
        $cron->hour = '*';
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        insert_record('cron', $cron);
    }
    if ($oldversion < 2011111500) {
        $table = new XMLDBTable('blocktype_installed_category');
        $key = new XMLDBKey('primary');
        $key->setAttributes(XMLDB_KEY_PRIMARY, array('blocktype'));
        add_key($table, $key);
    }
    if ($oldversion < 2011120200) {
        if ($data = check_upgrades('blocktype.blog/taggedposts')) {
            upgrade_plugin($data);
        }
        if ($data = check_upgrades('blocktype.watchlist')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2012011300) {
        $table = new XMLDBTable('group_member');
        $field = new XMLDBField('method');
        $field->setAttributes(XMLDB_TYPE_CHAR, 100, null, XMLDB_NOTNULL, null, null, null, 'internal');
        add_field($table, $field);
    }
    if ($oldversion < 2012021000) {
        $table = new XMLDBTable('usr');
        $field = new XMLDBField('unread');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
    }
    if ($oldversion < 2012021700) {
        $sql = "\n            FROM {usr} u JOIN {auth_instance} ai ON (u.authinstance = ai.id)\n            WHERE u.deleted = 0 AND ai.authname = 'internal' AND u.password != '*' AND u.salt != '*'";
        $pwcount = count_records_sql("SELECT COUNT(*) " . $sql);
        $sql = "\n            SELECT u.id, u.password, u.salt" . $sql . " AND u.id > ?\n            ORDER BY u.id";
        $done = 0;
        $lastid = 0;
        $limit = 2000;
        while ($users = get_records_sql_array($sql, array($lastid), 0, $limit)) {
            foreach ($users as $user) {
                // Wrap the old hashed password inside a SHA512 hash ($6$ is the identifier for SHA512)
                $user->password = crypt($user->password, '$6$' . substr(md5(get_config('passwordsaltmain') . $user->salt), 0, 16));
                // Drop the salt from the password as it may contain secrets that are not stored in the db
                // for example, the passwordsaltmain value
                $user->password = substr($user->password, 0, 3) . substr($user->password, 3 + 16);
                set_field('usr', 'password', $user->password, 'id', $user->id);
                remove_user_sessions($user->id);
                $lastid = $user->id;
            }
            $done += count($users);
            log_debug("Upgrading stored passwords: {$done}/{$pwcount}");
            set_time_limit(30);
        }
    }
    if ($oldversion < 2012022100) {
        reload_html_filters();
    }
    if ($oldversion < 2012042600 && !table_exists(new XMLDBTable('iframe_source'))) {
        // Tables for configurable safe iframe sources
        $table = new XMLDBTable('iframe_source_icon');
        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('domain', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('name'));
        create_table($table);
        $iframedomains = array('YouTube' => 'www.youtube.com', 'Vimeo' => 'vimeo.com', 'SlideShare' => 'www.slideshare.net', 'Glogster' => 'www.glogster.com', 'WikiEducator' => 'wikieducator.org', 'Voki' => 'voki.com');
        foreach ($iframedomains as $name => $domain) {
            insert_record('iframe_source_icon', (object) array('name' => $name, 'domain' => $domain));
        }
        $table = new XMLDBTable('iframe_source');
        $table->addFieldInfo('prefix', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('prefix'));
        $table->addKeyInfo('namefk', XMLDB_KEY_FOREIGN, array('name'), 'iframe_source_icon', array('name'));
        create_table($table);
        $iframesources = array('www.youtube.com/embed/' => 'YouTube', 'player.vimeo.com/video/' => 'Vimeo', 'www.slideshare.net/slideshow/embed_code/' => 'SlideShare', 'www.glogster.com/glog/' => 'Glogster', 'www.glogster.com/glog.php' => 'Glogster', 'edu.glogster.com/glog/' => 'Glogster', 'edu.glogster.com/glog.php' => 'Glogster', 'wikieducator.org/index.php' => 'WikiEducator', 'voki.com/php/' => 'Voki');
        foreach ($iframesources as $prefix => $name) {
            insert_record('iframe_source', (object) array('prefix' => $prefix, 'name' => $name));
        }
        $iframeregexp = '%^https?://(' . str_replace('.', '\\.', implode('|', array_keys($iframesources))) . ')%';
        set_config('iframeregexp', $iframeregexp);
    }
    if ($oldversion < 2012042800) {
        $table = new XMLDBTable('usr_registration');
        $field = new XMLDBField('extra');
        $field->setAttributes(XMLDB_TYPE_TEXT);
        add_field($table, $field);
    }
    if ($oldversion < 2012051500) {
        $table = new XMLDBTable('usr_registration');
        $field = new XMLDBField('authtype');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL, null, null, null, 'internal');
        add_field($table, $field);
        $key = new XMLDBKey('authtype');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('authtype'), 'auth_installed', array('name'));
        add_key($table, $key);
    }
    if ($oldversion < 2012053100) {
        // Clean url fields for usr, group, and view tables.
        $table = new XMLDBTable('usr');
        $field = new XMLDBField('urlid');
        $field->setAttributes(XMLDB_TYPE_CHAR, 30, null, null);
        add_field($table, $field);
        $index = new XMLDBIndex('urliduk');
        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('urlid'));
        add_index($table, $index);
        $table = new XMLDBTable('group');
        $field = new XMLDBField('urlid');
        $field->setAttributes(XMLDB_TYPE_CHAR, 30, null, null);
        add_field($table, $field);
        $index = new XMLDBIndex('urliduk');
        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('urlid'));
        add_index($table, $index);
        $table = new XMLDBTable('view');
        $field = new XMLDBField('urlid');
        $field->setAttributes(XMLDB_TYPE_CHAR, 100, null, null);
        add_field($table, $field);
        $index = new XMLDBIndex('urliduk');
        $index->setAttributes(XMLDB_INDEX_UNIQUE, array('urlid', 'owner', 'group', 'institution'));
        add_index($table, $index);
    }
    if ($oldversion < 2012060100) {
        // Collection submission
        $table = new XMLDBTable('collection');
        $field = new XMLDBField('submittedgroup');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10);
        add_field($table, $field);
        $field = new XMLDBField('submittedhost');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255);
        add_field($table, $field);
        $field = new XMLDBField('submittedtime');
        $field->setAttributes(XMLDB_TYPE_DATETIME);
        add_field($table, $field);
        $key = new XMLDBKey('submittedgroupfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('submittedgroup'), 'group', array('id'));
        add_key($table, $key);
        $key = new XMLDBKey('submittedhostfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('submittedhost'), 'host', array('wwwroot'));
        add_key($table, $key);
    }
    if ($oldversion < 2012062900) {
        // Add site registration data tables
        $table = new XMLDBTable('site_registration');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('time', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        create_table($table);
        $table = new XMLDBTable('site_registration_data');
        $table->addFieldInfo('registration_id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('field', XMLDB_TYPE_CHAR, 100, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('value', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('registration_id', 'field'));
        $table->addKeyInfo('regdatafk', XMLDB_KEY_FOREIGN, array('registration_id'), 'site_registration', array('id'));
        create_table($table);
    }
    if ($oldversion < 2012062901) {
        // Add institution registration data tables
        $table = new XMLDBTable('institution_registration');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('time', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('institution', XMLDB_TYPE_CHAR, 255, null, null);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('institutionfk', XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
        create_table($table);
        $table = new XMLDBTable('institution_registration_data');
        $table->addFieldInfo('registration_id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('field', XMLDB_TYPE_CHAR, 100, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('value', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('registration_id', 'field'));
        $table->addKeyInfo('regdatafk', XMLDB_KEY_FOREIGN, array('registration_id'), 'institution_registration', array('id'));
        create_table($table);
        // Install a cron job to collection institution registration data
        $cron = new StdClass();
        $cron->callfunction = 'cron_institution_registration_data';
        $cron->minute = rand(0, 59);
        $cron->hour = rand(0, 23);
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = rand(0, 6);
        insert_record('cron', $cron);
    }
    if ($oldversion < 2012062902) {
        // Add institution stats table
        $table = new XMLDBTable('institution_data');
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, XMLDB_NOTNULL);
        $table->addFieldInfo('institution', XMLDB_TYPE_CHAR, 255, null, null);
        $table->addFieldInfo('type', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('value', XMLDB_TYPE_TEXT, 'small', null);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('ctime', 'institution', 'type'));
        $table->addKeyInfo('institutionfk', XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
        create_table($table);
        // Insert cron jobs to save institution data
        $cron = new StdClass();
        $cron->callfunction = 'cron_institution_data_weekly';
        $cron->minute = 55;
        $cron->hour = 23;
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = 6;
        insert_record('cron', $cron);
        $cron = new StdClass();
        $cron->callfunction = 'cron_institution_data_daily';
        $cron->minute = 51;
        $cron->hour = 23;
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        insert_record('cron', $cron);
    }
    if ($oldversion < 2012070200) {
        $table = new XMLDBTable('collection');
        $field = new XMLDBField('group');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, null, null, null, null, null);
        add_field($table, $field);
        $field = new XMLDBField('institution');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null, null, null, null, null);
        add_field($table, $field);
        $field = new XMLDBField('owner');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, null);
        change_field_notnull($table, $field);
        // For PostgresSQL, change_field_notnull of $field=owner with precision = 10 BIGINT(10)
        // will add a temporary column, move data from owner column, remove the column 'owner'
        // and then rename the temporary column to 'owner'. Therefore, all indexes and foreign keys
        // related to column 'owner' will be removed
        if (is_postgres()) {
            $key = new XMLDBKey('owner');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('owner'), 'usr', array('id'));
            add_key($table, $key);
        }
        $key = new XMLDBKey('group');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('group'), 'group', array('id'));
        add_key($table, $key);
        $key = new XMLDBKey('institution');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
        add_key($table, $key);
        // Add constraints
        execute_sql('ALTER TABLE {collection} ADD CHECK (
            (owner IS NOT NULL AND "group" IS NULL     AND institution IS NULL) OR
            (owner IS NULL     AND "group" IS NOT NULL AND institution IS NULL) OR
            (owner IS NULL     AND "group" IS NULL     AND institution IS NOT NULL)
        )');
    }
    if ($oldversion < 2012070300) {
        $table = new XMLDBTable('group');
        $field = new XMLDBField('groupparticipationreports');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
    }
    if ($oldversion < 2012080200) {
        $sql = "\n            FROM {usr} u JOIN {auth_instance} ai ON (u.authinstance = ai.id)\n            WHERE u.deleted = 0 AND ai.authname = 'internal' AND u.password != '*' AND u.salt != '*'\n            AND u.password NOT LIKE '\$%'";
        $pwcount = count_records_sql("SELECT COUNT(*) " . $sql);
        $sql = "\n            SELECT u.id, u.password, u.salt" . $sql . " AND u.id > ?\n            ORDER BY u.id";
        $done = 0;
        $lastid = 0;
        $limit = 2000;
        while ($users = get_records_sql_array($sql, array($lastid), 0, $limit)) {
            foreach ($users as $user) {
                // Wrap the old hashed password inside a SHA512 hash ($6$ is the identifier for SHA512)
                $user->password = crypt($user->password, '$6$' . substr(md5(get_config('passwordsaltmain') . $user->salt), 0, 16));
                // Drop the salt from the password as it may contain secrets that are not stored in the db
                // for example, the passwordsaltmain value
                $user->password = substr($user->password, 0, 3) . substr($user->password, 3 + 16);
                set_field('usr', 'password', $user->password, 'id', $user->id);
                remove_user_sessions($user->id);
                $lastid = $user->id;
            }
            $done += count($users);
            log_debug("Upgrading stored passwords: {$done}/{$pwcount}");
            set_time_limit(30);
        }
    }
    if ($oldversion < 2012080300) {
        // For multi-tokens we need '|' aka pipe characters either side of their old single token
        execute_sql('UPDATE {usr_account_preference} SET value = \'|\' || value || \'|\'
                            WHERE field=\'mobileuploadtoken\' AND NOT value ' . db_ilike() . '\'|%|\'');
    }
    if ($oldversion < 2012080600) {
        // Every minute, poll an imap mailbox to see if there are new mail bounces
        $cron = new StdClass();
        $cron->callfunction = 'check_imap_for_bounces';
        $cron->minute = '*';
        $cron->hour = '*';
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        insert_record('cron', $cron);
    }
    if ($oldversion < 2012080601) {
        $table = new XMLDBTable('group');
        $field = new XMLDBField('editwindowstart');
        $field->setAttributes(XMLDB_TYPE_DATETIME);
        add_field($table, $field);
        $field = new XMLDBField('editwindowend');
        $field->setAttributes(XMLDB_TYPE_DATETIME);
        add_field($table, $field);
    }
    if ($oldversion < 2013011700) {
        set_config('defaultregistrationexpirylifetime', 1209600);
    }
    if ($oldversion < 2013012100) {
        $event = (object) array('name' => 'loginas');
        ensure_record_exists('event_type', $event, $event);
    }
    if ($oldversion < 2013012101) {
        $table = new XMLDBTable('event_log');
        $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('realusr', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('event', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('data', XMLDB_TYPE_TEXT, null, null, null);
        $table->addFieldInfo('time', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addKeyInfo('usrfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
        $table->addKeyInfo('realusrfk', XMLDB_KEY_FOREIGN, array('realusr'), 'usr', array('id'));
        create_table($table);
        $cron = new StdClass();
        $cron->callfunction = 'cron_event_log_expire';
        $cron->minute = 7;
        $cron->hour = 23;
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        insert_record('cron', $cron);
    }
    if ($oldversion < 2013020500) {
        $table = new XMLDBTable('artefact');
        $field = new XMLDBField('license');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255);
        add_field($table, $field);
        $field = new XMLDBField('licensor');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255);
        add_field($table, $field);
        $field = new XMLDBField('licensorurl');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255);
        add_field($table, $field);
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('licensedefault');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255);
        add_field($table, $field);
        $field = new XMLDBField('licensemandatory');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        $table = new XMLDBTable('artefact_license');
        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('displayname', XMLDB_TYPE_CHAR, 255, null, null);
        $table->addFieldInfo('shortname', XMLDB_TYPE_CHAR, 255, null, null);
        $table->addFieldInfo('icon', XMLDB_TYPE_CHAR, 255, null, null);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('name'));
        create_table($table);
    }
    if ($oldversion < 2013020501) {
        require_once 'license.php';
        install_licenses_default();
    }
    if ($oldversion < 2013032202) {
        require_once get_config('libroot') . 'license.php';
        set_field('usr_account_preference', 'value', LICENSE_INSTITUTION_DEFAULT, 'field', 'licensedefault', 'value', '-');
    }
    if ($oldversion < 2013050700) {
        $table = new XMLDBTable('collection_tag');
        $table->addFieldInfo('collection', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('tag', XMLDB_TYPE_CHAR, 128, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('collection', 'tag'));
        $table->addKeyInfo('collectionfk', XMLDB_KEY_FOREIGN, array('collection'), 'collection', array('id'));
        create_table($table);
    }
    if ($oldversion < 2013062600) {
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('dropdownmenu');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
    }
    if ($oldversion < 2013081400) {
        // We've made a change to how update_safe_iframe_regex() generates the regex
        // Call this function to make sure the stored value reflects that change.
        update_safe_iframe_regex();
    }
    if ($oldversion < 2013082100) {
        log_debug('Update database for flexible page layouts feature');
        log_debug('1. Create table view_rows_columns');
        $table = new XMLDBTable('view_rows_columns');
        $table->addFieldInfo('view', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('row', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL);
        $table->addFieldInfo('columns', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL);
        $table->addKeyInfo('viewfk', XMLDB_KEY_FOREIGN, array('view'), 'view', array('id'));
        create_table($table);
        log_debug('2. Remake the table view_layout as view_layout_columns');
        $table = new XMLDBTable('view_layout_columns');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('columns', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL);
        $table->addFieldInfo('widths', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('columnwidthuk', XMLDB_KEY_UNIQUE, array('columns', 'widths'));
        create_table($table);
        log_debug('3. Alter table view_layout');
        $table = new XMLDBTable('view_layout');
        $field = new XMLDBField('rows');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 1);
        add_field($table, $field);
        $field = new XMLDBField('iscustom');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        $field = new XMLDBField('layoutmenuorder');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        log_debug('4. Create table view_layout_rows_columns');
        $table = new XMLDBTable('view_layout_rows_columns');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('viewlayout', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('row', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL);
        $table->addFieldInfo('columns', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('rowfk', XMLDB_KEY_FOREIGN, array('viewlayout'), 'view_layout', array('id'));
        $table->addKeyInfo('columnsfk', XMLDB_KEY_FOREIGN, array('columns'), 'view_layout_columns', array('id'));
        create_table($table);
        log_debug('5. Create table usr_custom_layout');
        $table = new XMLDBTable('usr_custom_layout');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('layout', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('usrfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
        $table->addKeyInfo('layoutfk', XMLDB_KEY_FOREIGN, array('layout'), 'view_layout', array('id'));
        create_table($table);
        log_debug('6. Convert existing view_layout records into new-style view_layouts with just one row');
        $oldlayouts = get_records_array('view_layout', '', '', 'id', 'id, columns, widths');
        foreach ($oldlayouts as $layout) {
            // We don't actually need to populate the "rows", "iscustom" or "layoutmenuorder" columns,
            // because their defaults take care of that.
            // Check to see if there's a view_layout_columns record that matches its widths.
            $colsid = get_field('view_layout_columns', 'id', 'widths', $layout->widths);
            if (!$colsid) {
                $colsid = insert_record('view_layout_columns', (object) array('columns' => $layout->columns, 'widths' => $layout->widths), 'id', true);
            }
            // Now insert a record for it in view_layout_rows_columns, to represent its one row
            insert_record('view_layout_rows_columns', (object) array('viewlayout' => $layout->id, 'row' => 1, 'columns' => $colsid));
            // And also it needs a record in usr_custom_layout saying it belongs to the root user
            insert_record('usr_custom_layout', (object) array('usr' => 0, 'layout' => $layout->id));
        }
        log_debug('7. Drop the obsolete view_layout.columns and view_layout.widths fields');
        $table = new XMLDBTable('view_layout');
        $field = new XMLDBField('columns');
        drop_field($table, $field);
        $field = new XMLDBField('widths');
        drop_field($table, $field);
        log_debug('8. Update default values for tables view_layout, view_layout_columns and view_layout_rows_columns');
        install_view_layout_defaults();
        log_debug('9. Update the table "block_instance"');
        $table = new XMLDBTable('block_instance');
        $field = new XMLDBField('row');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 2, null, XMLDB_NOTNULL, null, null, null, 1);
        // This one tends to take a while...
        set_time_limit(30);
        add_field($table, $field);
        set_time_limit(30);
        // Refactor the block_instance.viewcolumnorderuk key so it includes row.
        $key = new XMLDBKey('viewcolumnorderuk');
        $key->setAttributes(XMLDB_KEY_UNIQUE, array('view', 'column', 'order'));
        // If this particular site has been around since before Mahara 1.2, this
        // will actually have been created as a unique index rather than a unique
        // key, so check for that first.
        $indexname = find_index_name($table, $key);
        if (preg_match('/uix$/', $indexname)) {
            $index = new XMLDBIndex($indexname);
            $index->setAttributes(XMLDB_INDEX_UNIQUE, array('view', 'column', 'order'));
            drop_index($table, $index);
        } else {
            drop_key($table, $key);
        }
        $key = new XMLDBKey('viewrowcolumnorderuk');
        $key->setAttributes(XMLDB_KEY_UNIQUE, array('view', 'row', 'column', 'order'));
        add_key($table, $key);
        log_debug('10. Add a "numrows" column to the views table.');
        // The default value of "1" will be correct
        // for all existing views, because they're using the old one-row layout style
        $table = new XMLDBTable('view');
        $field = new XMLDBField('numrows');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 2, null, XMLDB_NOTNULL, null, null, null, 1);
        add_field($table, $field);
        log_debug('11. Update the table "view_rows_columns" for existing pages');
        execute_sql('INSERT INTO {view_rows_columns} ("view", "row", "columns") SELECT v.id, 1, v.numcolumns FROM {view} v');
    }
    if ($oldversion < 2013091900) {
        // Create skin table...
        $table = new XMLDBTable('skin');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('title', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('description', XMLDB_TYPE_TEXT);
        $table->addFieldInfo('owner', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('type', XMLDB_TYPE_CHAR, 10, 'private', XMLDB_NOTNULL);
        $table->addFieldInfo('viewskin', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('bodybgimg', XMLDB_TYPE_INTEGER, 10);
        $table->addFieldInfo('viewbgimg', XMLDB_TYPE_INTEGER, 10);
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME);
        $table->addFieldInfo('mtime', XMLDB_TYPE_DATETIME);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('ownerfk', XMLDB_KEY_FOREIGN, array('owner'), 'usr', array('id'));
        create_table($table);
        // Create skin_favorites table...
        $table = new XMLDBTable('skin_favorites');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('user', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('favorites', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('userfk', XMLDB_KEY_FOREIGN, array('user'), 'usr', array('id'));
        create_table($table);
        // Create skin_fonts table...
        $table = new XMLDBTable('skin_fonts');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, 100, null, XMLDB_NOTNULL);
        $table->addFieldInfo('title', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('licence', XMLDB_TYPE_CHAR, 255);
        $table->addFieldInfo('notice', XMLDB_TYPE_TEXT);
        $table->addFieldInfo('previewfont', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('variants', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('fonttype', XMLDB_TYPE_CHAR, 10, 'site', XMLDB_NOTNULL);
        $table->addFieldInfo('onlyheading', XMLDB_TYPE_INTEGER, 1, 0, XMLDB_NOTNULL);
        $table->addFieldInfo('fontstack', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('genericfont', XMLDB_TYPE_CHAR, 10, null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('cursive', 'fantasy', 'monospace', 'sans-serif', 'serif'));
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('nameuk', XMLDB_KEY_UNIQUE, array('name'));
        create_table($table);
        // Set column 'skin' to 'view' table...
        $table = new XMLDBTable('view');
        $field = new XMLDBField('skin');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10);
        add_field($table, $field);
        require_once get_config('libroot') . 'skin.php';
        install_skins_default();
    }
    if ($oldversion < 2013091901) {
        // Add a "skins" table to institutions to record whether they've enabled skins or not
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('skins');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1, 'dropdownmenu');
        add_field($table, $field);
    }
    if ($oldversion < 2013092300) {
        $table = new XMLDBTable('import_entry_requests');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
        $table->addFieldInfo('importid', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('entryid', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('entryparent', XMLDB_TYPE_CHAR, 255, null, null);
        $table->addFieldInfo('strategy', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL);
        $table->addFieldInfo('ownerid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('entrytype', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('entrytitle', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('entrycontent', XMLDB_TYPE_TEXT, null, null, null);
        $table->addFieldInfo('duplicateditemids', XMLDB_TYPE_TEXT, null, null, null);
        $table->addFieldInfo('existingitemids', XMLDB_TYPE_TEXT, null, null, null);
        $table->addFieldInfo('artefactmapping', XMLDB_TYPE_TEXT, null, null, null);
        $table->addFieldInfo('decision', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('owneridfk', XMLDB_KEY_FOREIGN, array('ownerid'), 'usr', array('id'));
        create_table($table);
    }
    if ($oldversion < 2013092600) {
        //  When uploading file as attachment and attaching it to an artefact, the artefact id
        //  (in artefact field) and uploaded file artefact id (in attachment filed) are stored.
        //  For Resume composite types (educationhistory, employmenthistory, books, etc.) this
        //  is not enough. So we have to add item field to differentiate between e.g. different
        //  employments in employmenhistory and to which employment the user actually whishes to
        //  attach certain attachment...
        $table = new XMLDBTable('artefact_attachment');
        $field = new XMLDBField('item');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10);
        add_field($table, $field);
    }
    if ($oldversion < 2013112100) {
        // Add a new column 'last_processed_userid' to the table 'activity_queue' in order to
        // split multiple user activity notifications into chunks
        $table = new XMLDBTable('activity_queue');
        $field = new XMLDBField('last_processed_userid');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10);
        add_field($table, $field);
        $key = new XMLDBKey('last_processed_useridfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('last_processed_userid'), 'usr', array('id'));
        add_key($table, $key);
    }
    if ($oldversion < 2013112600) {
        // If a mahara site was upgraded from 1.0 then keys for the following tables
        // may be missing so we will check for them and if missing add them.
        // Normally when we create a foreign key, we create an index alongside it.
        // If these keys were created by the 1.1 upgrade script, they will be missing
        // those indexes. To get the index and the key in place, we have to re-create
        // the key.
        $table = new XMLDBTable('artefact_access_usr');
        $index = new XMLDBIndex('usrfk');
        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('usr'));
        if (!index_exists($table, $index)) {
            $field = new XMLDBField('usr');
            $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
            try {
                change_field_type($table, $field, true, true);
            } catch (SQLException $e) {
                log_warn("Couldn't change artefact_access_usr.usr column to NOT NULL (it probably contains some NULL values)");
            }
            $key = new XMLDBKey('usrfk');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a foreign key on column artefact_access_usr.usr referencing usr.id (the column probably contains some nonexistent user id's");
            }
        }
        $index = new XMLDBIndex('artefactfk');
        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('artefact'));
        if (!index_exists($table, $index)) {
            $field = new XMLDBField('artefact');
            $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
            try {
                change_field_type($table, $field, true, true);
            } catch (SQLException $e) {
                log_warn("Couldn't change artefact_access_usr.artefact column to NOT NULL (it probably contains some NULL values)");
            }
            $key = new XMLDBKey('artefactfk');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('artefact'), 'artefact', array('id'));
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a foreign key on column artefact_access_usr.artefact referencing artefact.id (the column probably contains some nonexistent artefact id's)");
            }
        }
        $key = new XMLDBKey('primary');
        $key->setAttributes(XMLDB_KEY_PRIMARY, array('usr', 'artefact'));
        if (!db_key_exists($table, $key)) {
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a primary key on table artefact_access_usr across columns (usr, artefact). (Probably the table contains some non-unique values in those columns)");
            }
        }
        $table = new XMLDBTable('artefact_access_role');
        $index = new XMLDBIndex('artefactfk');
        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('artefact'));
        if (!index_exists($table, $index)) {
            $field = new XMLDBField('artefact');
            $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
            try {
                change_field_type($table, $field, true, true);
            } catch (SQLException $e) {
                log_warn("Couldn't change artefact_access_role.artefact column to NOT NULL (it probably contains some NULL values)");
            }
            $key = new XMLDBKey('artefactfk');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('artefact'), 'artefact', array('id'));
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a foreign key on column artefact_access_role.artefact referencing artefact.id (the column probably contains some nonexistente artefact id's)");
            }
        }
        $key = new XMLDBKey('primary');
        $key->setAttributes(XMLDB_KEY_PRIMARY, array('role', 'artefact'));
        if (!db_key_exists($table, $key)) {
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a primary key on table artefact_access_role across columns (role, artefact). (Probably there are some non-unique values in those columns.)");
            }
        }
        $table = new XMLDBTable('artefact_attachment');
        $index = new XMLDBIndex('artefactfk');
        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('artefact'));
        if (!index_exists($table, $index)) {
            try {
                add_index($table, $index);
            } catch (SQLException $e) {
                log_warn("Couldn't set a non-unique index on column artefact_attachment.artefact");
            }
        }
        $table = new XMLDBTable('group');
        $key = new XMLDBKey('grouptypefk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('grouptype'), 'grouptype', array('name'));
        if (!db_key_exists($table, $key)) {
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a foreign key on column group.grouptype referencing grouptype.name (the column probably contains some nonexistent grouptypes)");
            }
        }
        $table = new XMLDBTable('grouptype_roles');
        $index = new XMLDBIndex('grouptypefk');
        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('grouptype'));
        if (!index_exists($table, $index)) {
            $key = new XMLDBKey('grouptypefk');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('grouptype'), 'grouptype', array('name'));
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a foreign key on column grouptype_roles.grouptype referencing grouptype.name (the column probably contains some nonexistent grouptypes");
            }
        }
        $key = new XMLDBKey('primary');
        $key->setAttributes(XMLDB_KEY_PRIMARY, array('grouptype', 'role'));
        if (!db_key_exists($table, $key)) {
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a primary key on table grouptype_roles across columns (grouptype, role). (Probably there are some non-unique values in those columns.)");
            }
        }
        $table = new XMLDBTable('view_autocreate_grouptype');
        $index = new XMLDBIndex('viewfk');
        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('view'));
        if (!index_exists($table, $index)) {
            $field = new XMLDBField('view');
            $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
            try {
                change_field_type($table, $field, true, true);
            } catch (SQLException $e) {
                log_warn("Couldn't change column view_autocreate_grouptype.view to NOT NULL (probably the column contains some NULL values)");
            }
            $key = new XMLDBKey('viewfk');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('view'), 'view', array('id'));
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a foreign key on column view_autocreate_grouptype.view referencing view.id (probably the column contains some nonexistent view IDs");
            }
        }
        $index = new XMLDBIndex('grouptypefk');
        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('grouptype'));
        if (!index_exists($table, $index)) {
            $key = new XMLDBKey('grouptypefk');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('grouptype'), 'grouptype', array('name'));
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a foreign key on column view_autocreate_grouptype.grouptype referencing grouptype.name (probably the column contains some nonexistent grouptypes");
            }
        }
        $key = new XMLDBKey('primary');
        $key->setAttributes(XMLDB_KEY_PRIMARY, array('view', 'grouptype'));
        if (!db_key_exists($table, $key)) {
            try {
                add_key($table, $key);
            } catch (SQLException $e) {
                log_warn("Couldn't set a primary key on table view_autocreate_grouptype across columns (view, grouptype). (Probably those columns contain some non-unique values.)");
            }
        }
    }
    if ($oldversion < 2013121300) {
        // view_rows_columns can be missing the 'id' column if upgrading from version
        // earlier than v1.8 and because we are adding a sequential primary column after
        // the table is already made we need to
        // - check that the column doesn't exist then add it without key or sequence
        // - update the values for the new id column to be sequential
        // - then add the primary key and finally make the column sequential
        if ($records = get_records_sql_array('SELECT * FROM {view_rows_columns}', array())) {
            if (empty($records[0]->id)) {
                $table = new XMLDBTable('view_rows_columns');
                $field = new XMLDBField('id');
                $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 1, 'view');
                add_field($table, $field);
                $x = 1;
                foreach ($records as $record) {
                    execute_sql('UPDATE {view_rows_columns} SET id = ? WHERE view = ? AND row = ? AND columns = ?', array($x, $record->view, $record->row, $record->columns));
                    $x++;
                }
                // we can't add a sequence on a field unless it has a primary key
                $key = new XMLDBKey('primary');
                $key->setAttributes(XMLDB_KEY_PRIMARY, array('id'));
                add_key($table, $key);
                $field = new XMLDBField('id');
                $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
                change_field_type($table, $field);
                // but when we change field type postgres drops the keys for the column so we need
                // to add the primary key back again - see line 2205 for more info
                if (is_postgres()) {
                    $key = new XMLDBKey('primary');
                    $key->setAttributes(XMLDB_KEY_PRIMARY, array('id'));
                    add_key($table, $key);
                }
            }
        }
    }
    if ($oldversion < 2014010700) {
        // If the usr_custom_layout.group column exists, it indicates that we this patch has already
        // been run and we should skip it.
        $table = new XMLDBTable('usr_custom_layout');
        $field = new XMLDBField('group');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, null, null, null, null, null, 'usr');
        if (!field_exists($table, $field)) {
            // Add a log output line here so that we can tell whether this patch ran or not.
            log_debug('Correcting custom layout table structures.');
            // fix issue where custom layouts saved in groups, site pages and institutions
            // were set to have usr = 0 because view owner was null
            $table = new XMLDBTable('usr_custom_layout');
            $field = new XMLDBField('usr');
            $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, null);
            change_field_notnull($table, $field);
            // For PostgresSQL, change_field_notnull creates a temporary column, moves data to new temp column
            // and then renames the temp column to 'usr'. Therefore, all indexes and foreign keys
            // related to column 'owner' will be removed
            if (is_postgres()) {
                $key = new XMLDBKey('usr');
                $key->setAttributes(XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
                add_key($table, $key);
            }
            $field = new XMLDBField('group');
            $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, null, null, null, null, null, 'usr');
            add_field($table, $field);
            $key = new XMLDBKey('groupfk');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('group'), 'group', array('id'));
            add_key($table, $key);
            $field = new XMLDBField('institution');
            $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null, null, null, null, null, 'group');
            add_field($table, $field);
            $key = new XMLDBKey('institutionfk');
            $key->setAttributes(XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
            add_key($table, $key);
            // update previous records
            // get custom layouts with usr = 0 which are not in default set
            $groupcustomlayouts = get_records_sql_array('SELECT ucl.layout FROM {usr_custom_layout} ucl
                                                         LEFT JOIN {view_layout} vl ON vl.id = ucl.layout
                                                         WHERE usr = 0 AND iscustom = 1
                                                         ORDER BY ucl.id', array());
            if ($groupcustomlayouts != false) {
                foreach ($groupcustomlayouts as $groupcustomlayout) {
                    // find views using this custom layout
                    $views = get_records_array('view', 'layout', $groupcustomlayout->layout, '', 'owner, "group", institution');
                    if ($views != false) {
                        foreach ($views as $view) {
                            if (isset($view->owner)) {
                                // view owned by individual
                                $recordexists = get_record('usr_custom_layout', 'usr', $view->owner, 'layout', $groupcustomlayout->layout);
                                if (!$recordexists) {
                                    // add new record into usr_custom_layout table
                                    $customlayout = new stdClass();
                                    $customlayout->usr = $view->owner;
                                    $customlayout->layout = $groupcustomlayout->layout;
                                    insert_record('usr_custom_layout', $customlayout, 'id');
                                }
                            } else {
                                if (isset($view->group)) {
                                    // view owned by group
                                    $recordexists = get_record('usr_custom_layout', 'group', $view->group, 'layout', $groupcustomlayout->layout);
                                    if (!$recordexists) {
                                        // add new record into usr_custom_layout table
                                        $customlayout = new stdClass();
                                        $customlayout->group = $view->group;
                                        $customlayout->layout = $groupcustomlayout->layout;
                                        insert_record('usr_custom_layout', $customlayout, 'id');
                                    }
                                } else {
                                    if (isset($view->institution)) {
                                        // view owned by group
                                        $recordexists = get_record('usr_custom_layout', 'institution', $view->institution, 'layout', $groupcustomlayout->layout);
                                        if (!$recordexists) {
                                            // add new record into usr_custom_layout table
                                            $customlayout = new stdClass();
                                            $customlayout->institution = $view->institution;
                                            $customlayout->layout = $groupcustomlayout->layout;
                                            insert_record('usr_custom_layout', $customlayout, 'id');
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // now remove this custom layout
                    $removedrecords = delete_records('usr_custom_layout', 'usr', '0', 'layout', $groupcustomlayout->layout);
                }
            }
        }
    }
    if ($oldversion < 2014010800) {
        $table = new XMLDBTable('institution_config');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('institution', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('field', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('value', XMLDB_TYPE_TEXT, 'small');
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('institutionfk', XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
        $table->addIndexInfo('instfielduk', XMLDB_INDEX_UNIQUE, array('institution', 'field'));
        create_table($table);
    }
    if ($oldversion < 2014010801) {
        // adding institution column to allow for different site content for each institution
        $table = new XMLDBTable('site_content');
        $field = new XMLDBField('institution');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null);
        add_field($table, $field);
        // resetting the primary key and updating what is currently there to be
        // the 'mahara' institution's site pages
        $key = new XMLDBKey('primary');
        $key->setAttributes(XMLDB_KEY_PRIMARY, array('name'));
        drop_key($table, $key);
        execute_sql("UPDATE {site_content} SET institution = ?", array('mahara'));
        $key = new XMLDBKey('primary');
        $key->setAttributes(XMLDB_KEY_PRIMARY, array('name', 'institution'));
        add_key($table, $key);
        $key = new XMLDBKey('institutionfk');
        $key->setAttributes(XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
        add_key($table, $key);
        // now add the default general pages for each existing institution with the values of
        // the 'mahara' institution. These can them be altered via Administration -> Institutions -> General pages
        $sitecontentarray = array();
        $sitecontents = get_records_array('site_content', 'institution', 'mahara');
        foreach ($sitecontents as $sitecontent) {
            $sitecontentarray[$sitecontent->name] = $sitecontent->content;
        }
        $pages = site_content_pages();
        $now = db_format_timestamp(time());
        $institutions = get_records_array('institution');
        foreach ($institutions as $institution) {
            if ($institution->name != 'mahara') {
                foreach ($pages as $name) {
                    $page = new stdClass();
                    $page->name = $name;
                    $page->ctime = $now;
                    $page->mtime = $now;
                    $page->content = $sitecontentarray[$name];
                    $page->institution = $institution->name;
                    insert_record('site_content', $page);
                    $pageconfig = new stdClass();
                    $pageconfig->institution = $institution->name;
                    $pageconfig->field = 'sitepages_' . $name;
                    $pageconfig->value = 'mahara';
                    insert_record('institution_config', $pageconfig);
                }
            }
        }
    }
    if ($oldversion < 2014021100) {
        // Reset the view's skin value, if the skin does not exist
        execute_sql("UPDATE {view} v SET skin = NULL WHERE v.skin IS NOT NULL AND NOT EXISTS (SELECT id FROM {skin} s WHERE v.skin = s.id)");
    }
    if ($oldversion < 2014021200) {
        // Adding new Creative Commons 4.0 licenses.
        // CC4.0 will be added only if:
        // -- The CC4.0 URL doesn't already exist;
        // -- And CC3.0 hasn't been deleted earlier.
        $license = new stdClass();
        $license->name = 'http://creativecommons.org/licenses/by-sa/4.0/';
        $license->displayname = get_string('licensedisplaynamebysa', 'install');
        $license->shortname = get_string('licenseshortnamebysa', 'install');
        $license->icon = 'license:by-sa.png';
        $version30 = 'http://creativecommons.org/licenses/by-sa/3.0/';
        if (!record_exists('artefact_license', 'name', $license->name) && record_exists('artefact_license', 'name', $version30)) {
            insert_record('artefact_license', $license);
        }
        $license = new stdClass();
        $license->name = 'http://creativecommons.org/licenses/by/4.0/';
        $license->displayname = get_string('licensedisplaynameby', 'install');
        $license->shortname = get_string('licenseshortnameby', 'install');
        $license->icon = 'license:by.png';
        $version30 = 'http://creativecommons.org/licenses/by/3.0/';
        if (!record_exists('artefact_license', 'name', $license->name) && record_exists('artefact_license', 'name', $version30)) {
            insert_record('artefact_license', $license);
        }
        $license = new stdClass();
        $license->name = 'http://creativecommons.org/licenses/by-nd/4.0/';
        $license->displayname = get_string('licensedisplaynamebynd', 'install');
        $license->shortname = get_string('licenseshortnamebynd', 'install');
        $license->icon = 'license:by-nd.png';
        $version30 = 'http://creativecommons.org/licenses/by-nd/3.0/';
        if (!record_exists('artefact_license', 'name', $license->name) && record_exists('artefact_license', 'name', $version30)) {
            insert_record('artefact_license', $license);
        }
        $license = new stdClass();
        $license->name = 'http://creativecommons.org/licenses/by-nc-sa/4.0/';
        $license->displayname = get_string('licensedisplaynamebyncsa', 'install');
        $license->shortname = get_string('licenseshortnamebyncsa', 'install');
        $license->icon = 'license:by-nc-sa.png';
        $version30 = 'http://creativecommons.org/licenses/by-nc-sa/3.0/';
        if (!record_exists('artefact_license', 'name', $license->name) && record_exists('artefact_license', 'name', $version30)) {
            insert_record('artefact_license', $license);
        }
        $license = new stdClass();
        $license->name = 'http://creativecommons.org/licenses/by-nc/4.0/';
        $license->displayname = get_string('licensedisplaynamebync', 'install');
        $license->shortname = get_string('licenseshortnamebync', 'install');
        $license->icon = 'license:by-nc.png';
        $version30 = 'http://creativecommons.org/licenses/by-nc/3.0/';
        if (!record_exists('artefact_license', 'name', $license->name) && record_exists('artefact_license', 'name', $version30)) {
            insert_record('artefact_license', $license);
        }
        $license = new stdClass();
        $license->name = 'http://creativecommons.org/licenses/by-nc-nd/4.0/';
        $license->displayname = get_string('licensedisplaynamebyncnd', 'install');
        $license->shortname = get_string('licenseshortnamebyncnd', 'install');
        $license->icon = 'license:by-nc-nd.png';
        $version30 = 'http://creativecommons.org/licenses/by-nc-nd/3.0/';
        if (!record_exists('artefact_license', 'name', $license->name) && record_exists('artefact_license', 'name', $version30)) {
            insert_record('artefact_license', $license);
        }
    }
    if ($oldversion < 2014022400) {
        // Make sure artefacts are properly locked for submitted views.
        // Can be a problem for older sites
        $submitted = get_records_sql_array("SELECT v.owner FROM {view_artefact} va\n                        LEFT JOIN {view} v on v.id = va.view\n                        LEFT JOIN {artefact} a on a.id = va.artefact\n                        WHERE (v.submittedgroup IS NOT NULL OR v.submittedhost IS NOT NULL)", array());
        if ($submitted) {
            require_once get_config('docroot') . 'artefact/lib.php';
            foreach ($submitted as $record) {
                ArtefactType::update_locked($record->owner);
            }
        }
    }
    if ($oldversion < 2014022600) {
        $table = new XMLDBTable('host');
        $field = new XMLDBField('portno');
        drop_field($table, $field);
    }
    if ($oldversion < 2014032400) {
        $table = new XMLDBTable('group');
        $field = new XMLDBField('sendnow');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
    }
    if ($oldversion < 2014032500) {
        $table = new XMLDBTable('usr');
        $field = new XMLDBField('probation');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
    }
    if ($oldversion < 2014032600) {
        set_config('watchlistnotification_delay', 20);
        if (!table_exists(new XMLDBTable('watchlist_queue'))) {
            $table = new XMLDBTable('watchlist_queue');
            $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
            $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
            $table->addFieldInfo('block', XMLDB_TYPE_INTEGER, 10, null, false);
            $table->addFieldInfo('view', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
            $table->addFieldInfo('changed_on', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
            $table->addKeyInfo('viewfk', XMLDB_KEY_FOREIGN, array('view'), 'view', array('id'));
            $table->addKeyInfo('blockfk', XMLDB_KEY_FOREIGN, array('block'), 'block_instance', array('id'));
            $table->addKeyInfo('usrfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
            $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
            create_table($table);
        }
        // new event type: delete blockinstance
        $e = new stdClass();
        $e->name = 'deleteblockinstance';
        ensure_record_exists('event_type', $e, $e);
        // install the core event subscriptions
        $subs = array(array('event' => 'blockinstancecommit', 'callfunction' => 'watchlist_record_changes'), array('event' => 'deleteblockinstance', 'callfunction' => 'watchlist_block_deleted'), array('event' => 'saveartefact', 'callfunction' => 'watchlist_record_changes'), array('event' => 'saveview', 'callfunction' => 'watchlist_record_changes'));
        foreach ($subs as $sub) {
            ensure_record_exists('event_subscription', (object) $sub, (object) $sub);
        }
        // install the cronjobs...
        $cron = new stdClass();
        $cron->callfunction = 'watchlist_process_notifications';
        $cron->minute = '*';
        $cron->hour = '*';
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        ensure_record_exists('cron', $cron, $cron);
    }
    if ($oldversion < 2014032700) {
        // Remove bad data created by the upload user via csv where users in no institution
        // have 'licensedefault' set causing an error
        execute_sql("DELETE FROM {usr_account_preference} WHERE FIELD = 'licensedefault' AND usr IN (\n                        SELECT u.id FROM {usr} u\n                        LEFT JOIN {usr_institution} ui ON ui.usr = u.id\n                        WHERE ui.institution = 'mahara' OR ui.institution is null\n                     )");
    }
    if ($oldversion < 2014040300) {
        // Figure out where the magicdb is, and stick with that.
        require_once get_config('libroot') . 'file.php';
        update_magicdb_path();
    }
    // Add id field and corresponding index to institution table.
    if ($oldversion < 2014040400) {
        $table = new XMLDBTable('institution');
        // Add id field.
        $field = new XMLDBField('id');
        if (!field_exists($table, $field)) {
            // Field.
            $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 1, 'name');
            add_field($table, $field);
            // Update ids.
            $institutions = get_records_array('institution');
            $x = 1;
            foreach ($institutions as $institution) {
                execute_sql('UPDATE {institution} SET id = ? WHERE name = ?', array($x, $institution->name));
                $x++;
            }
            $key = new XMLDBKey('inst_id_uk');
            $key->setAttributes(XMLDB_KEY_UNIQUE, array('id'));
            add_key($table, $key);
            // Add sequence.
            $field = new XMLDBField('id');
            $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
            change_field_type($table, $field);
            // In postgres, keys and indexes are removed when a field is changed ("Add sequence" above), so add the key back.
            if (is_postgres()) {
                $key = new XMLDBKey('inst_id_uk');
                $key->setAttributes(XMLDB_KEY_UNIQUE, array('id'));
                add_key($table, $key);
            }
        }
    }
    if ($oldversion < 2014041401) {
        $table = new XMLDBTable('institution');
        $field = new XMLDBField('registerallowed');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, '0');
        change_field_default($table, $field);
    }
    if ($oldversion < 2014041600) {
        // Add allownonemethod and defaultmethod fields to activity_type table.
        $table = new XMLDBTable('activity_type');
        $field = new XMLDBField('allownonemethod');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL, null, null, null, 1, 'delay');
        add_field($table, $field);
        $field = new XMLDBField('defaultmethod');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null, null, null, null, 'email', 'allownonemethod');
        add_field($table, $field);
        // Allow null method in usr_activity_preference.
        // Null indicates "none", no record indicates "not yet set" so use the default.
        $table = new XMLDBTable('usr_activity_preference');
        $field = new XMLDBField('method');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null, null, null, null, null);
        change_field_notnull($table, $field);
    }
    // Add about me block to existing profile template.
    if ($oldversion < 2014043000) {
        $systemprofileviewid = get_field('view', 'id', 'owner', 0, 'type', 'profile');
        // Find out how many blocks already exist.
        $maxorder = get_field_sql('select max("order") from {block_instance} where "view"=? and "row"=? and "column"=?', array($systemprofileviewid, 1, 1));
        // Create the block at the end of the cell.
        require_once get_config('docroot') . 'blocktype/lib.php';
        $aboutme = new BlockInstance(0, array('blocktype' => 'profileinfo', 'title' => get_string('aboutme', 'blocktype.internal/profileinfo'), 'view' => $systemprofileviewid, 'row' => 1, 'column' => 1, 'order' => $maxorder + 1));
        $aboutme->commit();
        // Move the block to the start of the cell.
        require_once get_config('libroot') . 'view.php';
        $view = new View($systemprofileviewid);
        $view->moveblockinstance(array('id' => $aboutme->get('id'), 'row' => 1, 'column' => 1, 'order' => 1));
    }
    if ($oldversion < 2014050901) {
        require_once get_config('docroot') . 'artefact/lib.php';
        // First drop artefact_parent_cache table.
        $table = new XMLDBTable('artefact_parent_cache');
        drop_table($table, true);
        // Remove cron jobs from DB.
        delete_records('cron', 'callfunction', 'rebuild_artefact_parent_cache_dirty');
        delete_records('cron', 'callfunction', 'rebuild_artefact_parent_cache_complete');
        // Add path field to artefact table.
        $table = new XMLDBTable('artefact');
        $field = new XMLDBField('path');
        $field->setAttributes(XMLDB_TYPE_CHAR, '1024', null, null, null, null, null);
        add_field($table, $field);
        // Fill the new field with path data.
        // Set all artefacts to the path they'd have if they have no parent.
        log_debug('Filling in parent artefact paths');
        if (get_config('searchplugin') == 'elasticsearch') {
            log_debug('Dropping elasticsearch artefact triggers');
            require_once get_config('docroot') . 'search/elasticsearch/lib.php';
            ElasticsearchIndexing::drop_triggers('artefact');
        }
        $count = 0;
        $limit = 1000;
        $limitsmall = 200;
        $total = count_records_select('artefact', 'path IS NULL AND parent IS NULL');
        for ($i = 0; $i <= $total; $i += $limitsmall) {
            if (is_mysql()) {
                execute_sql("UPDATE {artefact} SET path = CONCAT('/', id) WHERE path IS NULL AND parent IS NULL LIMIT " . $limitsmall);
            } else {
                // Postgres can only handle limit in subquery
                execute_sql("UPDATE {artefact} SET path = CONCAT('/', id) WHERE id IN (SELECT id FROM {artefact} WHERE path IS NULL AND parent IS NULL LIMIT " . $limitsmall . ")");
            }
            $count += $limitsmall;
            if ($count % $limit == 0 || $count >= $total) {
                if ($count > $total) {
                    $count = $total;
                }
                log_debug("{$count}/{$total}");
                set_time_limit(30);
            }
        }
        $newcount = count_records_select('artefact', 'path IS NULL');
        if ($newcount) {
            $childlevel = 0;
            do {
                $childlevel++;
                $lastcount = $newcount;
                log_debug("Filling in level-{$childlevel} child artefact paths");
                if (is_postgres()) {
                    execute_sql("\n                        UPDATE {artefact}\n                        SET path = p.path || '/' || {artefact}.id\n                        FROM {artefact} p\n                        WHERE\n                            {artefact}.parent=p.id\n                            AND {artefact}.path IS NULL\n                            AND p.path IS NOT NULL\n                    ");
                } else {
                    execute_sql("\n                        UPDATE\n                            {artefact} a\n                            INNER JOIN {artefact} p\n                            ON a.parent = p.id\n                        SET a.path=p.path || '/' || a.id\n                        WHERE\n                            a.path IS NULL\n                            AND p.path IS NOT NULL\n                    ");
                }
                $newcount = count_records_select('artefact', 'path IS NULL');
                // There may be some bad records whose paths can't be filled in,
                // so stop looping if the count stops going down.
            } while ($newcount > 0 && $newcount < $lastcount);
            log_debug("Done filling in child artefact paths");
        }
        if (get_config('searchplugin') == 'elasticsearch') {
            log_debug("Add triggers back in");
            ElasticsearchIndexing::create_triggers('artefact');
        }
    }
    // Make objectionable independent of view_access page.
    if ($oldversion < 2014060300) {
        log_debug("Create 'objectionable' table.");
        $table = new XMLDBTable('objectionable');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('objecttype', XMLDB_TYPE_CHAR, 20, null, XMLDB_NOTNULL);
        $table->addFieldInfo('objectid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('reportedby', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('report', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL);
        $table->addFieldInfo('reportedtime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('resolvedby', XMLDB_TYPE_INTEGER, 10, null, null);
        $table->addFieldInfo('resolvedtime', XMLDB_TYPE_DATETIME, null, null);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('reporterfk', XMLDB_KEY_FOREIGN, array('reportedby'), 'usr', array('id'));
        $table->addKeyInfo('resolverfk', XMLDB_KEY_FOREIGN, array('resolvedby'), 'usr', array('id'));
        $table->addIndexInfo('objectix', XMLDB_INDEX_NOTUNIQUE, array('objectid', 'objecttype'));
        create_table($table);
        // Migrate data to a new format.
        // Since we don't have report or name of the user, use root ID.
        // Table 'notification_internal_activity' contains data that is
        // not possible to extract in any reasonable way.
        $objectionable = get_records_array('view_access', 'accesstype', 'objectionable');
        db_begin();
        log_debug('Migrating objectionable records to new format');
        if (!empty($objectionable)) {
            $count = 0;
            $limit = 1000;
            $total = count($objectionable);
            foreach ($objectionable as $record) {
                $todb = new stdClass();
                $todb->objecttype = 'view';
                $todb->objectid = $record->view;
                $todb->reportedby = 0;
                $todb->report = '';
                $todb->reportedtime = $record->ctime ? $record->ctime : format_date(time());
                if (!empty($record->stopdate)) {
                    // Since we can't get an ID of a user who resolved an issue, use root ID.
                    $todb->resolvedby = 0;
                    $todb->resolvedtime = $record->stopdate;
                }
                insert_record('objectionable', $todb);
                $count++;
                if ($count % $limit == 0 || $count == $total) {
                    log_debug("{$count}/{$total}");
                    set_time_limit(30);
                }
            }
        }
        // Delete data from 'view_access' table as we don't need it any more.
        delete_records('view_access', 'accesstype', 'objectionable');
        db_commit();
        log_debug("Drop constraint on 'view_access'");
        // Need to run this to avoid contraints problems on Postgres.
        if (is_postgres()) {
            execute_sql('ALTER TABLE {view_access} DROP CONSTRAINT {viewacce_acc_ck}');
        }
        log_debug("Update 'view_access' accesstype");
        // Update accesstype in 'view_access' not to use 'objectionable'.
        $table = new XMLDBTable('view_access');
        $field = new XMLDBField('accesstype');
        $field->setAttributes(XMLDB_TYPE_CHAR, 16, null, null, null, XMLDB_ENUM, array('public', 'loggedin', 'friends'));
        change_field_enum($table, $field);
    }
    if ($oldversion < 2014060500) {
        log_debug("Add 'artefact_access' table.");
        $table = new XMLDBTable('artefact_access');
        $table->addFieldInfo('artefact', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('accesstype', XMLDB_TYPE_CHAR, 16, null, null, null, XMLDB_ENUM, array('public', 'loggedin', 'friends'));
        $table->addFieldInfo('group', XMLDB_TYPE_INTEGER, 10);
        $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10);
        $table->addFieldInfo('institution', XMLDB_TYPE_CHAR, 255);
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addKeyInfo('artefactfk', XMLDB_KEY_FOREIGN, array('artefact'), 'artefact', array('id'));
        $table->addKeyInfo('groupfk', XMLDB_KEY_FOREIGN, array('group'), 'group', array('id'));
        $table->addKeyInfo('usrfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
        $table->addKeyInfo('institutionfk', XMLDB_KEY_FOREIGN, array('institution'), 'institution', array('name'));
        $table->addIndexInfo('accesstypeix', XMLDB_INDEX_NOTUNIQUE, array('accesstype'));
        create_table($table);
    }
    if ($oldversion < 2014061100) {
        log_debug('Add module related tables');
        $table = new XMLDBTable('module_installed');
        $table->addFieldInfo('name', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('version', XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('release', XMLDB_TYPE_TEXT, 'small', XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('active', XMLDB_TYPE_INTEGER, 1, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 1);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('name'));
        create_table($table);
        $table = new XMLDBTable('module_cron');
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('callfunction', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('minute', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('hour', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('day', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('dayofweek', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('month', XMLDB_TYPE_CHAR, 25, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '*');
        $table->addFieldInfo('nextrun', XMLDB_TYPE_DATETIME, null, null);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('plugin', 'callfunction'));
        $table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'module_installed', array('name'));
        create_table($table);
        $table = new XMLDBTable('module_config');
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 100, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('field', XMLDB_TYPE_CHAR, 100, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('value', XMLDB_TYPE_TEXT, 'small', XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('plugin', 'field'));
        $table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'module_installed', array('name'));
        create_table($table);
        $table = new XMLDBTable('module_event_subscription');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
        $table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('event', XMLDB_TYPE_CHAR, 50, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addFieldInfo('callfunction', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'module_installed', array('name'));
        $table->addKeyInfo('eventfk', XMLDB_KEY_FOREIGN, array('event'), 'event_type', array('name'));
        $table->addKeyInfo('subscruk', XMLDB_KEY_UNIQUE, array('plugin', 'event', 'callfunction'));
        create_table($table);
    }
    if ($oldversion < 2014062000) {
        log_debug('Fix up auth_clean_expired_password_requests cron');
        $where = array('callfunction' => 'auth_clean_expired_password_requests');
        $data = array('callfunction' => 'auth_clean_expired_password_requests', 'minute' => '5', 'hour' => '0', 'day' => '*', 'month' => '*', 'dayofweek' => '*');
        ensure_record_exists('cron', (object) $where, (object) $data);
    }
    if ($oldversion < 2014062500) {
        log_debug("Add 'feedbacknotify' option to 'group' table");
        require_once get_config('libroot') . 'group.php';
        $table = new XMLDBTable('group');
        $field = new XMLDBField('feedbacknotify');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, GROUP_ROLES_ALL);
        if (!field_exists($table, $field)) {
            add_field($table, $field);
        }
    }
    if ($oldversion < 2014073100) {
        log_debug('Delete leftover data which are not associated to any institution');
        // Institution collections
        $collectionids = get_column_sql('
            SELECT id
            FROM {collection} c
            WHERE c.institution IS NOT NULL
                AND NOT EXISTS (SELECT 1 FROM {institution} i WHERE i.name = c.institution)');
        if ($collectionids) {
            require_once get_config('libroot') . 'collection.php';
            $count = 0;
            $limit = 200;
            $total = count($collectionids);
            foreach ($collectionids as $collectionid) {
                $collection = new Collection($collectionid);
                $collection->delete();
                $count++;
                if ($count % $limit == 0) {
                    log_debug("Deleting leftover collections: {$count}/{$total}");
                    set_time_limit(30);
                }
            }
            log_debug("Deleting leftover collections: {$count}/{$total}");
        }
        log_debug('Delete leftover custom layouts / usr registration');
        // Institution custom layouts and registration
        delete_records_sql('
            DELETE FROM {usr_custom_layout}
            WHERE {usr_custom_layout}.institution IS NOT NULL
                AND NOT EXISTS (SELECT 1 FROM {institution} i WHERE i.name = {usr_custom_layout}.institution)');
        delete_records_sql('
            DELETE FROM {usr_registration}
            WHERE {usr_registration}.institution IS NOT NULL
                AND NOT EXISTS (SELECT 1 FROM {institution} i WHERE i.name = {usr_registration}.institution)');
    }
    if ($oldversion < 2014081900) {
        log_debug("Check blocktype 'text' is installed");
        if ($data = check_upgrades('blocktype.text')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2014091600) {
        log_debug('Allow anonymous pages');
        $table = new XMLDBTable('view');
        $field = new XMLDBField('anonymise');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        set_config('allowanonymouspages', 0);
    }
    if ($oldversion < 2014091800) {
        log_debug("Add 'allowarchives' column to the 'group' table");
        $table = new XMLDBTable('group');
        $field = new XMLDBField('allowarchives');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        add_field($table, $field);
        log_debug("Add 'submittedstatus' column to 'view' table");
        $table = new XMLDBTable('view');
        $field = new XMLDBField('submittedstatus');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0, 'submittedtime');
        add_field($table, $field);
        log_debug("Need to update the submitted status for any existing views that are submitted");
        execute_sql('UPDATE {view} SET submittedstatus = 1 WHERE submittedgroup IS NOT NULL
                    AND submittedtime IS NOT NULL');
        log_debug("Add 'submittedstatus' column to 'collection' table");
        $table = new XMLDBTable('collection');
        $field = new XMLDBField('submittedstatus');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0, 'submittedtime');
        add_field($table, $field);
        log_debug('Need to update the submitted status for any existing collections that are submitted');
        execute_sql('UPDATE {collection} SET submittedstatus = 1 WHERE submittedgroup IS NOT NULL
                    AND submittedtime IS NOT NULL');
        log_debug('Adding the export queue / submission tables');
        // Add export queue table - each export is one row.
        $table = new XMLDBTable('export_queue');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('type', XMLDB_TYPE_CHAR, 50);
        $table->addFieldInfo('exporttype', XMLDB_TYPE_CHAR, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addFieldInfo('starttime', XMLDB_TYPE_DATETIME);
        $table->addFieldInfo('externalid', XMLDB_TYPE_CHAR, 255);
        $table->addFieldInfo('submitter', XMLDB_TYPE_INTEGER, 10);
        // for when the submitter is not the owner
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('usrfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
        $table->addKeyInfo('submitterfk', XMLDB_KEY_FOREIGN, array('submitter'), 'usr', array('id'));
        create_table($table);
        // Add export queue items table which maps what views/collections/artefacts relate to the queue item.
        $table = new XMLDBTable('export_queue_items');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('exportqueueid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('collection', XMLDB_TYPE_INTEGER, 10);
        $table->addFieldInfo('view', XMLDB_TYPE_INTEGER, 10);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('exportqueuefk', XMLDB_KEY_FOREIGN, array('exportqueueid'), 'export_queue', array('id'));
        $table->addKeyInfo('collectionfk', XMLDB_KEY_FOREIGN, array('collection'), 'collection', array('id'));
        $table->addKeyInfo('viewfk', XMLDB_KEY_FOREIGN, array('view'), 'view', array('id'));
        create_table($table);
        // Add export archive table to hold info that will allow one to download the zip file
        $table = new XMLDBTable('export_archive');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('filename', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('filetitle', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('filepath', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL);
        $table->addFieldInfo('submission', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 0);
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('usrfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
        create_table($table);
        // Add archived submissions table to hold submission info
        $table = new XMLDBTable('archived_submissions');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('archiveid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL);
        $table->addFieldInfo('group', XMLDB_TYPE_INTEGER, 10);
        $table->addFieldInfo('externalhost', XMLDB_TYPE_CHAR, 50);
        $table->addFieldInfo('externalid', XMLDB_TYPE_CHAR, 255);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('groupfk', XMLDB_KEY_FOREIGN, array('group'), 'group', array('id'));
        $table->addKeyInfo('archivefk', XMLDB_KEY_FOREIGN, array('archiveid'), 'export_archive', array('id'));
        create_table($table);
        // install the cronjob to process export queue
        $cron = new StdClass();
        $cron->callfunction = 'export_process_queue';
        $cron->minute = '*/6';
        $cron->hour = '*';
        $cron->day = '*';
        $cron->month = '*';
        $cron->dayofweek = '*';
        ensure_record_exists('cron', $cron, $cron);
        // install the cronjob to clean up deleted archived submissions items
        $cron = new StdClass();
        $cron->callfunction = 'submissions_delete_removed_archive';
        $cron->minute = '15';
        $cron->hour = '1';
        $cron->day = '1';
        $cron->month = '*';
        $cron->dayofweek = '*';
        ensure_record_exists('cron', $cron, $cron);
    }
    if ($oldversion < 2014092300) {
        log_debug('Add the socialprofile artefacttype');
        // Need to insert directly into the table instead of running upgrade_plugin(), so that we can transition
        // all the old social network artefact types into the new unified socialprofile type before deleting
        // the old types from artefact_installed_type
        insert_record('artefact_installed_type', (object) array('name' => 'socialprofile', 'plugin' => 'internal'));
        // Convert existing messaging types to socialprofile types.
        $oldmessagingfieldsarray = array('icqnumber', 'msnnumber', 'aimscreenname', 'yahoochat', 'skypeusername', 'jabberusername');
        $oldmessagingfields = implode(',', array_map('db_quote', $oldmessagingfieldsarray));
        $sql = "SELECT * FROM {artefact}\n                WHERE artefacttype IN (" . $oldmessagingfields . ")";
        if ($results = get_records_sql_assoc($sql, array())) {
            $count = 0;
            $limit = 1000;
            $total = count($results);
            safe_require('artefact', 'internal');
            foreach ($results as $result) {
                $i = new ArtefactTypeSocialprofile($result->id, (array) $result);
                $i->set('artefacttype', 'socialprofile');
                switch ($result->artefacttype) {
                    case 'aimscreenname':
                        $i->set('note', 'aim');
                        $i->set('description', get_string('aim', 'artefact.internal'));
                        break;
                    case 'icqnumber':
                        $i->set('note', 'icq');
                        $i->set('description', get_string('icq', 'artefact.internal'));
                        break;
                    case 'jabberusername':
                        $i->set('note', 'jabber');
                        $i->set('description', get_string('jabber', 'artefact.internal'));
                        break;
                    case 'msnnumber':
                    case 'skypeusername':
                        // MSN no longer exists and has been replaced by Skype.
                        $i->set('note', 'skype');
                        $i->set('description', get_string('skype', 'artefact.internal'));
                        break;
                    case 'yahoochat':
                        $i->set('note', 'yahoo');
                        $i->set('description', get_string('yahoo', 'artefact.internal'));
                        break;
                }
                $i->set('title', $result->title);
                $i->commit();
                $count++;
                if ($count % $limit == 0 || $count == $total) {
                    log_debug("{$count}/{$total}");
                    set_time_limit(30);
                }
            }
        }
        $sql = "SELECT value FROM {search_config} WHERE plugin='elasticsearch' AND field='artefacttypesmap'";
        if ($result = get_field_sql($sql, array())) {
            log_debug('Clean up elasticsearch fields for the old messaging fields');
            $artefacttypesmap_array = explode("\n", $result);
            $elasticsearchartefacttypesmap = array();
            foreach ($artefacttypesmap_array as $key => $value) {
                $tmpkey = explode("|", $value);
                if (count($tmpkey) == 3) {
                    if (!in_array($tmpkey[0], $oldmessagingfieldsarray)) {
                        // we're going to keep this one.
                        $elasticsearchartefacttypesmap[] = $value;
                    }
                }
            }
            // add socialprofile field.
            $elasticsearchartefacttypesmap[] = "socialprofile|Profile|Text";
            // now save the data excluding the old messaging fields.
            set_config_plugin('search', 'elasticsearch', 'artefacttypesmap', implode("\n", $elasticsearchartefacttypesmap));
        }
        log_debug('Delete unused, but still installed artefact types');
        delete_records_select("artefact_installed_type", "name IN (" . $oldmessagingfields . ")");
        log_debug('Install the social profile blocktype so users can see their migrated data');
        if ($data = check_upgrades('blocktype.internal/socialprofile')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2014092300) {
        log_debug("Install 'multirecipientnotification' plugin");
        if ($data = check_upgrades('module.multirecipientnotification')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2014101300) {
        log_debug("Make sure default notifications are not set to 'none'");
        // Make sure the 'system messages' and 'messages from other users' have a notification method set
        // It was possible after earlier upgrades to set method to 'none'.
        // Also make sure old defaultmethod is respected.
        $activitytypes = get_records_assoc('activity_type');
        foreach ($activitytypes as $type) {
            $type->defaultmethod = get_config('defaultnotificationmethod') ? get_config('defaultnotificationmethod') : 'email';
            if ($type->name == 'maharamessage' || $type->name == 'usermessage') {
                $type->allownonemethod = 0;
            }
            update_record('activity_type', $type);
        }
        // Make sure users have their 'system messages' and 'messages from other users' notification method set
        if ($useractivities = get_records_sql_assoc("SELECT * FROM {activity_type} at, {usr_activity_preference} uap\n                                                     WHERE at.id = uap.activity\n                                                     AND at.name IN ('maharamessage', 'usermessage')\n                                                     AND (method IS NULL OR method = '')", array())) {
            foreach ($useractivities as $activity) {
                $userprefs = new stdClass();
                $userprefs->method = $activity->defaultmethod;
                update_record('usr_activity_preference', $userprefs, array('usr' => $activity->usr, 'activity' => $activity->activity));
            }
        }
    }
    if ($oldversion < 2014101500) {
        log_debug('Place skin fonts in their correct directories');
        if ($fonts = get_records_assoc('skin_fonts', 'fonttype', 'google')) {
            $fontpath = get_config('dataroot') . 'skins/fonts/';
            foreach ($fonts as $font) {
                // if google font is not already in subdir
                if (!is_dir($fontpath . $font->name)) {
                    if (file_exists($fontpath . $font->previewfont)) {
                        // we need to create the subdir and move the file into it
                        $newfontpath = $fontpath . $font->name . '/';
                        check_dir_exists($newfontpath, true, true);
                        rename($fontpath . $font->previewfont, $newfontpath . $font->previewfont);
                        // and move the license file if it exists also
                        if (file_exists($fontpath . $font->licence)) {
                            rename($fontpath . $font->licence, $newfontpath . $font->licence);
                        }
                    } else {
                        // the file is not there for some reason so we might as well delete the font from the db
                        $result = delete_records('skin_fonts', 'name', $font->name);
                        if ($result !== false) {
                            // Check to see if the font is being used in a skin. If it is remove it from
                            // the skin's viewskin data
                            $skins = get_records_array('skin');
                            if (is_array($skins)) {
                                foreach ($skins as $skin) {
                                    $options = unserialize($skin->viewskin);
                                    foreach ($options as $key => $option) {
                                        if (preg_match('/font_family/', $key) && $option == $font->name) {
                                            require_once get_config('docroot') . 'lib/skin.php';
                                            $skinobj = new Skin($skin->id);
                                            $viewskin = $skinobj->get('viewskin');
                                            $viewskin[$key] = false;
                                            $skinobj->set('viewskin', $viewskin);
                                            $skinobj->commit();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    if ($oldversion < 2014101501) {
        log_debug('Unlock root user grouphomepage template in case it is locked');
        set_field('view', 'locked', 0, 'type', 'grouphomepage', 'owner', 0);
    }
    if ($oldversion < 2014110500) {
        log_debug('Add cacheversion and assign random string');
        // Adding cacheversion, as an arbitrary number appended to the end of JS & CSS files in order
        // to tell cacheing software when they've been updated. (Without having to use the Mahara
        // minor version for that purpose.)
        // Set this to a random starting number to make minor version slightly harder to detect
        if (!get_config('cacheversion')) {
            set_config('cacheversion', rand(1000, 9999));
        }
    }
    if ($oldversion < 2014110700) {
        log_debug("Add in 'shortcut' category to 'blocktype_category'");
        // Increment all the existing sorts by 1 to make room...
        $cats = get_records_array('blocktype_category', '', '', 'sort desc');
        foreach ($cats as $cat) {
            $cat->sort = $cat->sort + 1;
            update_record('blocktype_category', $cat, 'name');
        }
        $todb = new stdClass();
        $todb->name = 'shortcut';
        $todb->sort = '0';
        insert_record('blocktype_category', $todb);
    }
    if ($oldversion < 2014112700) {
        log_debug("Fix up group homepages so that no duplicate 'groupview' blocks are present");
        // Need to find the group homepages that have more than one groupview on them
        // and merge their data into one groupview as we shouldn't allow more than one groupview block
        // as it breaks pagination
        // First get any pages that have more than one groupview on them
        // and find the status of the groupview blocks
        if ($records = get_records_sql_array("SELECT v.id AS view, bi.id AS block FROM {view} v\n            INNER JOIN {block_instance} bi ON v.id = bi.view\n            WHERE v.id IN (\n                SELECT v.id FROM {view} v\n                 INNER JOIN {block_instance} bi ON v.id = bi.view\n                 WHERE bi.blocktype = 'groupviews'\n                  AND v.type = 'grouphomepage'\n                 GROUP BY v.id\n                 HAVING COUNT(v.id) > 1\n            )\n            AND bi.blocktype='groupviews'\n            ORDER BY v.id, bi.id", array())) {
            require_once get_config('docroot') . 'blocktype/lib.php';
            $lastview = 0;
            // set default
            $info = array();
            $x = -1;
            foreach ($records as $record) {
                if ($lastview != $record->view) {
                    $x++;
                    $info[$x]['in']['showgroupviews'] = 0;
                    $info[$x]['in']['showsharedviews'] = 0;
                    $info[$x]['in']['view'] = $record->view;
                    $info[$x]['in']['block'] = $record->block;
                    $lastview = $record->view;
                } else {
                    $info[$x]['out'][] = $record->block;
                }
                $bi = new BlockInstance($record->block);
                $configdata = $bi->get('configdata');
                if (!empty($configdata['showgroupviews'])) {
                    $info[$x]['in']['showgroupviews'] = 1;
                }
                if (!empty($configdata['showsharedviews'])) {
                    $info[$x]['in']['showsharedviews'] = 1;
                }
            }
            // now that we have info on the state of play we need to save one of the blocks
            // with correct data and delete the not needed blocks
            $count = 0;
            $limit = 1000;
            $total = count($info);
            foreach ($info as $item) {
                $bi = new BlockInstance($item['in']['block']);
                $configdata = $bi->get('configdata');
                $configdata['showgroupviews'] = $item['in']['showgroupviews'];
                $configdata['showsharedviews'] = $item['in']['showsharedviews'];
                $bi->set('configdata', $configdata);
                $bi->commit();
                foreach ($item['out'] as $old) {
                    $bi = new BlockInstance($old);
                    $bi->delete();
                }
                $count++;
                if ($count % $limit == 0 || $count == $total) {
                    log_debug("{$count}/{$total}");
                    set_time_limit(30);
                }
            }
        }
    }
    if ($oldversion < 2014121200) {
        log_debug('Remove layout preview thumbs directory');
        require_once 'file.php';
        $layoutdir = get_config('dataroot') . 'images/layoutpreviewthumbs';
        if (file_exists($layoutdir)) {
            rmdirr($layoutdir);
        }
    }
    if ($oldversion < 2015013000) {
        log_debug("Add a 'sortorder' column to 'blocktype_installed_category'");
        // Add a sortorder column to blocktype_installed_category
        $table = new XMLDBTable('blocktype_installed_category');
        $field = new XMLDBField('sortorder');
        $field->setAttributes(XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null, null, 100000, 'category');
        add_field($table, $field);
    }
    if ($oldversion < 2015021000) {
        log_debug('Need to update any dashboard pages to not have skins');
        // and seen as we are updating and selecting from the same table
        // we need to use a temptable for it to work in mysql
        execute_Sql("UPDATE {view} SET skin = NULL WHERE id IN ( SELECT vid FROM (SELECT id AS vid FROM {view} WHERE type = 'dashboard' AND skin IS NOT NULL) AS temptable)");
    }
    if ($oldversion < 2015021900) {
        log_debug('Remove bbcode formatting from existing wall posts');
        require_once get_config('docroot') . '/lib/stringparser_bbcode/lib.php';
        if ($records = get_records_sql_array("SELECT id, text FROM {blocktype_wall_post} WHERE text LIKE '%[%'", array())) {
            foreach ($records as &$r) {
                $r->text = parse_bbcode($r->text);
                update_record('blocktype_wall_post', $r);
            }
        }
    }
    if ($oldversion < 2015030400) {
        log_debug("Update search config settings");
        if (get_config('searchusernames') === 1) {
            set_config('nousernames', 0);
        } else {
            set_config('nousernames', 1);
        }
        delete_records('config', 'field', 'searchusernames');
    }
    if ($oldversion < 2015032600) {
        log_debug("Update block categories for plugins");
        if ($blocktypes = plugins_installed('blocktype', true)) {
            foreach ($blocktypes as $bt) {
                install_blocktype_categories_for_plugin(blocktype_single_to_namespaced($bt->name, $bt->artefactplugin));
            }
        }
    }
    if ($oldversion < 2015033000) {
        log_debug("Updating TinyMCE emoticon locations in mahara database");
        // Seeing as tinymce has moved the location of the emoticons
        // we need to fix up a few places where users could have added emoticons.
        // $replacements is key = table, value = column
        $replacements = array('view' => 'description', 'artefact' => 'title', 'artefact' => 'description', 'group' => 'description', 'interaction_forum_post' => 'body', 'notification_internal_activity' => 'message', 'blocktype_wall_post' => 'text', 'site_content' => 'content');
        foreach ($replacements as $key => $value) {
            execute_sql("UPDATE {" . $key . "} SET " . $value . " = REPLACE(" . $value . ", '/emotions/img', '/emoticons/img') WHERE " . $value . " LIKE '%/emotions/img%'");
        }
        // we need to handle block_instance configdata in a special way
        if ($results = get_records_sql_array("SELECT id FROM {block_instance} WHERE configdata LIKE '%/emotions/img%'", array())) {
            log_debug("Updating 'block_instance' data for TinyMCE");
            require_once get_config('docroot') . 'blocktype/lib.php';
            $count = 0;
            $limit = 1000;
            $total = count($results);
            foreach ($results as $result) {
                $bi = new BlockInstance($result->id);
                $configdata = $bi->get('configdata');
                foreach ($configdata as $key => $value) {
                    $configdata[$key] = preg_replace('/\\/emotions\\/img/', '/emotions/img', $value);
                }
                $bi->set('configdata', $configdata);
                $bi->commit();
                $count++;
                if ($count % $limit == 0 || $count == $total) {
                    log_debug("{$count}/{$total}");
                    set_time_limit(30);
                }
            }
        }
    }
    if ($oldversion < 2015041400) {
        log_debug('Force install of annotation and webservices plugins');
        if ($data = check_upgrades('artefact.annotation')) {
            upgrade_plugin($data);
        }
        if ($data = check_upgrades('auth.webservice')) {
            upgrade_plugin($data);
        }
    }
    if ($oldversion < 2015042800) {
        log_debug('Clear Dwoo cache of unescaped institution names');
        require_once 'dwoo/dwoo/dwooAutoload.php';
        @unlink(get_config('dataroot') . 'dwoo/compile/default' . get_config('docroot') . 'theme/raw/' . 'templates/view/accesslistrow.tpl.d' . Dwoo_Core::RELEASE_TAG . '.php');
        @unlink(get_config('dataroot') . 'dwoo/compile/default' . get_config('docroot') . 'theme/raw/' . 'templates/admin/users/accesslistitem.tpl.d' . Dwoo_Core::RELEASE_TAG . '.php');
    }
    if ($oldversion < 2015071500) {
        log_debug('Expanding the size of the import_entry_requests.entrycontent column');
        $table = new XMLDBTable('import_entry_requests');
        $field = new XMLDBField('entrycontent');
        $field->setType(XMLDB_TYPE_TEXT);
        $field->setLength('big');
        change_field_precision($table, $field);
    }
    if ($oldversion < 2015072000) {
        // If we are upgrading from a site built before 2014092300 straight to 15.10
        // then the plugin won't exist as an artefact.
        if (table_exists(new XMLDBTable('artefact_multirecipient_userrelation'))) {
            log_debug('Change installation of artefact plugin multirecipentNotification to plugin module.');
            // first, drop the old triggers
            db_drop_trigger('update_unread_insert2', 'artefact_multirecipient_userrelation');
            db_drop_trigger('update_unread_update2', 'artefact_multirecipient_userrelation');
            db_drop_trigger('update_unread_delete2', 'artefact_multirecipient_userrelation');
            // rename tables artefact_multirecipientnotifiaction_notification and
            // Table: artefact_multirecipient_userrelation to module-prefix
            execute_sql("ALTER TABLE {artefact_multirecipient_notification} RENAME TO {module_multirecipient_notification}");
            execute_sql("ALTER TABLE {artefact_multirecipient_userrelation} RENAME TO {module_multirecipient_userrelation}");
            if (is_postgres()) {
                // Rename seq artefact_multirecipientnotifiaction_notification_id_seq and
                // artefact_multirecipient_userrelation_id_seq
                execute_sql("ALTER SEQUENCE {artefact_multirecipient_notification_id_seq} RENAME TO {module_multirecipient_notification_id_seq}");
                execute_sql("ALTER SEQUENCE {artefact_multirecipient_userrelation_id_seq} RENAME TO {module_multirecipient_userrelation_id_seq}");
            }
            //move event_subscrition entries for artefact plugin
            //multirecipientnotification to table module_event_subscription
            $subscriptions = get_records_array('artefact_event_subscription', 'plugin', 'multirecipientnotification');
            delete_records('artefact_event_subscription', 'plugin', 'multirecipientnotification');
            delete_records('artefact_installed_type', 'plugin', 'multirecipientnotification');
            $installrecord = get_record('artefact_installed', 'name', 'multirecipientnotification');
            if (is_object($installrecord)) {
                insert_record('module_installed', $installrecord);
                delete_records('artefact_installed', 'name', 'multirecipientnotification');
            }
            if (is_array($subscriptions)) {
                foreach ($subscriptions as $subscription) {
                    insert_record('module_event_subscription', $subscription, 'id');
                }
            }
            // recreate trigger
            safe_require('module', 'multirecipientnotification');
            PluginModuleMultirecipientnotification::postinst(0);
        }
    }
    if ($oldversion < 2015081000) {
        log_debug('Add user_login_data table to record when a user logs in');
        $table = new XMLDBTable('usr_login_data');
        $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
        $table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, false, XMLDB_NOTNULL);
        $table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
        $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->addKeyInfo('usrloginfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
        create_table($table);
        // Insert info about current users's logins
        $results = get_records_sql_array("SELECT id,lastlogin FROM {usr} WHERE deleted = 0 AND lastlogin IS NOT NULL");
        $count = 0;
        $limit = 1000;
        $total = count($results);
        foreach ($results as $result) {
            insert_record('usr_login_data', (object) array('usr' => $result->id, 'ctime' => $result->lastlogin));
            $count++;
            if ($count % $limit == 0 || $count == $total) {
                log_debug("{$count}/{$total}");
                set_time_limit(30);
            }
        }
    }
    if ($oldversion < 2015081700) {
        // In 15.10, we changed the registration site policy.
        // We need to remind the site admins to register the site again with the new policy.
        log_debug('Remind the site admins to register the site again with the new policy');
        if (get_config('new_registration_policy') != -1) {
            set_config('new_registration_policy', true);
        }
        if (get_config('registration_sendweeklyupdates')) {
            set_config('registration_sendweeklyupdates', false);
        }
    }
    if ($oldversion < 2015082500) {
        // Add a site default portfolio page template
        log_debug('Add a site default portfolio page template');
        require_once 'view.php';
        install_system_portfolio_view();
    }
    if ($oldversion < 2015091700) {
        log_debug('Update cached customizable theme CSS');
        $styles = get_records_array('institution', 'theme', 'custom', 'id', 'displayname, style');
        if ($styles) {
            foreach ($styles as $newinstitution) {
                $styleid = $newinstitution->style;
                $properties = array();
                $record = (object) array('style' => $styleid);
                $proprecs = get_records_array('style_property', 'style', $styleid, 'field', 'field, value');
                foreach ($proprecs as $p) {
                    $properties[$p->field] = $p->value;
                }
                // Update the css
                $smarty = smarty_core();
                $smarty->assign('data', $properties);
                set_field('style', 'css', $smarty->fetch('customcss.tpl'), 'id', $styleid);
            }
        }
    }
    return $status;
}
Example #3
0
/**
 * This function will drop the key in the table passed as arguments.
 * Before dropping the key, the function will check it exists.
 *
 * @uses $CFG, $db
 * @param XMLDBTable table object (just the name is mandatory)
 * @param XMLDBKey key object (full specs are required)
 * @param boolean continue to specify if must continue on error (true) or stop (false)
 * @param boolean feedback to specify to show status info (true) or not (false)
 * @return boolean true on success, false on error
 */
function drop_key($table, $key, $continue = true, $feedback = true)
{
    global $CFG, $db;
    $status = true;
    if (strtolower(get_class($table)) != 'xmldbtable') {
        return false;
    }
    if (strtolower(get_class($key)) != 'xmldbkey') {
        return false;
    }
    // Check key exists.
    if (!db_key_exists($table, $key)) {
        debugging('Key ' . $key->getName() . ' does not exist. Delete skipped', DEBUG_DEVELOPER);
        return true;
        // Key doesn't exist, nothing to do.
    }
    if (!($sqlarr = $table->getDropKeySQL($CFG->dbtype, $CFG->prefix, $key, false))) {
        return true;
        //Empty array = nothing to do = no error
    }
    return execute_sql_arr($sqlarr, $continue, $feedback);
}