From: skodak Date: Thu, 3 Jan 2008 15:03:32 +0000 (+0000) Subject: MDL-6786 Improved dropping of block and module tables during uninstall; merged from... X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=8293c751987fd89fa6b59c8f549ddcda7a8698b0;p=moodle.git MDL-6786 Improved dropping of block and module tables during uninstall; merged from MOODLE_19_STABLE --- diff --git a/admin/blocks.php b/admin/blocks.php index b9c6cc3f5a..277645a49b 100644 --- a/admin/blocks.php +++ b/admin/blocks.php @@ -100,25 +100,9 @@ notify("Error occurred while deleting the $strblockname record from blocks table"); } - // Then the tables themselves - if ($tables = $db->Metatables()) { - $prefix = $CFG->prefix.$block->name; - $prefix2 = $CFG->prefix.'block_'.$block->name; - foreach ($tables as $table) { - if (strpos($table, $prefix) === 0 || strpos($table, $prefix2) === 0) { - /// If the match has been due to the 1st condition, debug to developers - if (strpos($table, $prefix) === 0) { - debugging('This block has some wrongly named tables. See Moodle Docs coding guidelines (and MDL-6786)', DEBUG_DEVELOPER); - } - /// Strip prefix from $table - $table = preg_replace("/^{$CFG->prefix}/", '', $table); - $xmldb_table = new XMLDBTable($table); - if (!drop_table($xmldb_table, true, false)) { - notify("ERROR: while trying to drop table $table"); - } - } - } - } + drop_plugin_tables($block->name, "$CFG->dirroot/blocks/$block->name/db/install.xml", false); // old obsoleted table names + drop_plugin_tables('block_'.$block->name, "$CFG->dirroot/blocks/$block->name/db/install.xml", false); + // Delete the capabilities that were defined by this block capabilities_cleanup('block/'.$block->name); diff --git a/admin/modules.php b/admin/modules.php index 8471c74181..c550dfd33e 100644 --- a/admin/modules.php +++ b/admin/modules.php @@ -5,6 +5,7 @@ require_once('../course/lib.php'); require_once($CFG->libdir.'/adminlib.php'); require_once($CFG->libdir.'/tablelib.php'); + require_once($CFG->libdir.'/ddllib.php'); // defines define('MODULE_TABLE','module_administration_table'); @@ -139,17 +140,8 @@ } // Then the tables themselves + drop_plugin_tables($module->name, "$CFG->dirroot/mod/$module->name/db/install.xml", false); - if ($tables = $db->Metatables()) { - $prefix = $CFG->prefix.$module->name; - foreach ($tables as $table) { - if (strpos($table, $prefix) === 0) { - if (!execute_sql("DROP TABLE $table", false)) { - notify("ERROR: while trying to drop table $table"); - } - } - } - } // Delete the capabilities that were defined by this module capabilities_cleanup('mod/'.$module->name); diff --git a/admin/xmldb/actions/get_db_directories/get_db_directories.class.php b/admin/xmldb/actions/get_db_directories/get_db_directories.class.php index 918d69ed6a..608e298095 100644 --- a/admin/xmldb/actions/get_db_directories/get_db_directories.class.php +++ b/admin/xmldb/actions/get_db_directories/get_db_directories.class.php @@ -70,111 +70,17 @@ class get_db_directories extends XMLDBAction { if (!isset($XMLDB->dbdirs)) { $XMLDB->dbdirs = array(); } - /// First, the main one (lib/db) - $dbdir = new stdClass; - $dbdir->path = $CFG->libdir . '/db'; - if (!isset($XMLDB->dbdirs[$dbdir->path])) { - $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } - $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - - /// Now, activity modules (mod/xxx/db) - if ($plugins = get_list_of_plugins('mod')) { - foreach ($plugins as $plugin) { - $dbdir = new stdClass; - $dbdir->path = $CFG->dirroot . '/mod/' . $plugin . '/db'; - if (!isset($XMLDB->dbdirs[$dbdir->path])) { - $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } - $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - } - } - - /// Now, assignment submodules (mod/assignment/type/xxx/db) - if ($plugins = get_list_of_plugins('mod/assignment/type')) { - foreach ($plugins as $plugin) { - $dbdir = new stdClass; - $dbdir->path = $CFG->dirroot . '/mod/assignment/type/' . $plugin . '/db'; - if (!isset($XMLDB->dbdirs[$dbdir->path])) { - $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } - $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - } - } - - /// Now, question types (question/type/xxx/db) - if ($plugins = get_list_of_plugins('question/type')) { - foreach ($plugins as $plugin) { - $dbdir = new stdClass; - $dbdir->path = $CFG->dirroot . '/question/type/' . $plugin . '/db'; - if (!isset($XMLDB->dbdirs[$dbdir->path])) { - $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } - $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - } - } - - /// Now, backup/restore stuff (backup/db) - $dbdir = new stdClass; - $dbdir->path = $CFG->dirroot . '/backup/db'; - if (!isset($XMLDB->dbdirs[$dbdir->path])) { - $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } - $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - /// Now, block system stuff (blocks/db) - $dbdir = new stdClass; - $dbdir->path = $CFG->dirroot . '/blocks/db'; - if (!isset($XMLDB->dbdirs[$dbdir->path])) { - $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } - $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - - /// Now, blocks (blocks/xxx/db) - if ($plugins = get_list_of_plugins('blocks', 'db')) { - foreach ($plugins as $plugin) { - $dbdir = new stdClass; - $dbdir->path = $CFG->dirroot . '/blocks/' . $plugin . '/db'; - if (!isset($XMLDB->dbdirs[$dbdir->path])) { - $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } - $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - } - } - - /// Now, course formats (course/format/xxx/db) - if ($plugins = get_list_of_plugins('course/format', 'db')) { - foreach ($plugins as $plugin) { - $dbdir = new stdClass; - $dbdir->path = $CFG->dirroot . '/course/format/' . $plugin . '/db'; - if (!isset($XMLDB->dbdirs[$dbdir->path])) { - $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } - $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - } - } - - /// Now, enrolment plugins (enrol/xxx/db) - if ($plugins = get_list_of_plugins('enrol', 'db')) { - foreach ($plugins as $plugin) { - $dbdir = new stdClass; - $dbdir->path = $CFG->dirroot . '/enrol/' . $plugin . '/db'; - if (!isset($XMLDB->dbdirs[$dbdir->path])) { - $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } - $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - } - } - - /// Local database changes, if the local folder exists. - if (file_exists($CFG->dirroot . '/local')) { + /// get list of all dirs and create objects with status + $db_direcotries = get_db_directories(); + foreach ($db_direcotries as $path) { $dbdir = new stdClass; - $dbdir->path = $CFG->dirroot . '/local/db'; + $dbdir->path = $path; if (!isset($XMLDB->dbdirs[$dbdir->path])) { $XMLDB->dbdirs[$dbdir->path] = $dbdir; - } + } $XMLDB->dbdirs[$dbdir->path]->path_exists = file_exists($dbdir->path); //Update status - } + } /// Sort by key ksort($XMLDB->dbdirs); diff --git a/lib/ddllib.php b/lib/ddllib.php index 3538de89e3..576a7cd379 100644 --- a/lib/ddllib.php +++ b/lib/ddllib.php @@ -635,6 +635,193 @@ function install_from_xmldb_file($file) { return execute_sql_arr($sqlarr); } +/** + * This function will all tables found in XMLDB file from db + * + * @uses $CFG, $db + * @param $file full path to the XML file to be used + * @param $feedback + * @return boolean (true on success, false on error) + */ +function delete_tables_from_xmldb_file($file, $feedback=true ) { + + global $CFG, $db; + + $status = true; + + + $xmldb_file = new XMLDBFile($file); + + if (!$xmldb_file->fileExists()) { + return false; + } + + $loaded = $xmldb_file->loadXMLStructure(); + $structure =& $xmldb_file->getStructure(); + + if (!$loaded || !$xmldb_file->isLoaded()) { + /// Show info about the error if we can find it + if ($feedback and $structure) { + if ($errors = $structure->getAllErrors()) { + notify('Errors found in XMLDB file: '. implode (', ', $errors)); + } + } + return false; + } + + if ($tables = $structure->getTables()) { + foreach($tables as $table) { + if (table_exists($table)) { + drop_table($table, true, $feedback); + } + } + } + + return true; +} + +/** + * Delete all plugin tables + * @name string name of plugin, used as table prefix + * @file string path to install.xml file + * @feedback boolean + */ +function drop_plugin_tables($name, $file, $feedback=true) { + global $CFG, $db; + + // first try normal delete + if (delete_tables_from_xmldb_file($file, $feedback)) { + return true; + } + + // then try to find all tables that start with name and are not in any xml file + $used_tables = get_used_table_names(); + + $tables = $db->MetaTables(); + /// Iterate over, fixing id fields as necessary + foreach ($tables as $table) { + if (strlen($CFG->prefix)) { + if (strpos($table, $CFG->prefix) !== 0) { + continue; + } + $table = substr($table, strlen($CFG->prefix)); + } + $table = strtolower($table); + if (strpos($table, $name) !== 0) { + continue; + } + if (in_array($table, $used_tables)) { + continue; + } + + // found orphan table --> delete it + $table = new XMLDBTable($table); + if (table_exists($table)) { + drop_table($table, true, $feedback); + } + } + + return true; +} + +/** + * Returns names of all known tables == tables that moodle knowns about. + * @return array of lowercase table names + */ +function get_used_table_names() { + $table_names = array(); + $dbdirs = get_db_directories(); + + foreach ($dbdirs as $dbdir) { + $file = $dbdir.'/install.xml'; + + $xmldb_file = new XMLDBFile($file); + + if (!$xmldb_file->fileExists()) { + continue; + } + + $loaded = $xmldb_file->loadXMLStructure(); + $structure =& $xmldb_file->getStructure(); + + if ($loaded and $tables = $structure->getTables()) { + foreach($tables as $table) { + $table_names[] = strtolower($table->name); + } + } + } + + return $table_names; +} + +/** + * Returns list of all directories where we expect install.xml files + * @return array of paths + */ +function get_db_directories() { + global $CFG; + + $dbdirs = array(); + +/// First, the main one (lib/db) + $dbdirs[] = $CFG->libdir.'/db'; + +/// Now, activity modules (mod/xxx/db) + if ($plugins = get_list_of_plugins('mod')) { + foreach ($plugins as $plugin) { + $dbdirs[] = $CFG->dirroot.'/mod/'.$plugin.'/db'; + } + } + +/// Now, assignment submodules (mod/assignment/type/xxx/db) + if ($plugins = get_list_of_plugins('mod/assignment/type')) { + foreach ($plugins as $plugin) { + $dbdirs[] = $CFG->dirroot.'/mod/assignment/type/'.$plugin.'/db'; + } + } + +/// Now, question types (question/type/xxx/db) + if ($plugins = get_list_of_plugins('question/type')) { + foreach ($plugins as $plugin) { + $dbdirs[] = $CFG->dirroot.'/question/type/'.$plugin.'/db'; + } + } + +/// Now, backup/restore stuff (backup/db) + $dbdirs[] = $CFG->dirroot.'/backup/db'; + +/// Now, block system stuff (blocks/db) + $dbdirs[] = $CFG->dirroot.'/blocks/db'; + +/// Now, blocks (blocks/xxx/db) + if ($plugins = get_list_of_plugins('blocks', 'db')) { + foreach ($plugins as $plugin) { + $dbdirs[] = $CFG->dirroot.'/blocks/'.$plugin.'/db'; + } + } + +/// Now, course formats (course/format/xxx/db) + if ($plugins = get_list_of_plugins('course/format', 'db')) { + foreach ($plugins as $plugin) { + $dbdirs[] = $CFG->dirroot.'/course/format/'.$plugin.'/db'; + } + } + +/// Now, enrolment plugins (enrol/xxx/db) + if ($plugins = get_list_of_plugins('enrol', 'db')) { + foreach ($plugins as $plugin) { + $dbdirs[] = $CFG->dirroot.'/enrol/'.$plugin.'/db'; + } + } + +/// Local database changes, if the local folder exists. + if (file_exists($CFG->dirroot . '/local')) { + $dbdirs[] = $CFG->dirroot.'/local/db'; + } + + return $dbdirs; +} + /** * This function will create the table passed as argument with all its * fields/keys/indexes/sequences, everything based in the XMLDB object