|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00018 00031 defined('MOODLE_INTERNAL') || die(); 00032 00038 class database_manager { 00039 00040 protected $mdb; 00041 public $generator; // public because XMLDB editor needs to access it 00042 00047 public function __construct($mdb, $generator) { 00048 global $CFG; 00049 00050 $this->mdb = $mdb; 00051 $this->generator = $generator; 00052 } 00053 00057 public function dispose() { 00058 if ($this->generator) { 00059 $this->generator->dispose(); 00060 $this->generator = null; 00061 } 00062 $this->mdb = null; 00063 } 00064 00073 protected function execute_sql_arr(array $sqlarr) { 00074 foreach ($sqlarr as $sql) { 00075 $this->execute_sql($sql); 00076 } 00077 } 00078 00087 protected function execute_sql($sql) { 00088 if (!$this->mdb->change_database_structure($sql)) { 00089 // in case driver does not throw exceptions yet ;-) 00090 throw new ddl_change_structure_exception($this->mdb->get_last_error(), $sql); 00091 } 00092 } 00093 00100 public function table_exists($table) { 00101 if (!is_string($table) and !($table instanceof xmldb_table)) { 00102 throw new ddl_exception('ddlunknownerror', NULL, 'incorrect table parameter!'); 00103 } 00104 return $this->generator->table_exists($table); 00105 } 00106 00112 public function reset_sequence($table) { 00113 if (!is_string($table) and !($table instanceof xmldb_table)) { 00114 throw new ddl_exception('ddlunknownerror', NULL, 'incorrect table parameter!'); 00115 } 00116 00118 if (!$this->table_exists($table)) { 00119 throw new ddl_table_missing_exception($table); 00120 } 00121 00122 if (!$sqlarr = $this->generator->getResetSequenceSQL($table)) { 00123 throw new ddl_exception('ddlunknownerror', null, 'table reset sequence sql not generated'); 00124 } 00125 00126 $this->execute_sql_arr($sqlarr); 00127 } 00128 00136 public function field_exists($table, $field) { 00138 if (is_string($table)) { 00139 $tablename = $table; 00140 } else { 00141 $tablename = $table->getName(); 00142 } 00143 00145 if (!$this->table_exists($table)) { 00146 throw new ddl_table_missing_exception($tablename); 00147 } 00148 00149 if (is_string($field)) { 00150 $fieldname = $field; 00151 } else { 00153 $fieldname = $field->getName(); 00154 } 00155 00157 $columns = $this->mdb->get_columns($tablename); 00158 00159 $exists = array_key_exists($fieldname, $columns); 00160 00161 return $exists; 00162 } 00163 00172 public function find_index_name(xmldb_table $xmldb_table, xmldb_index $xmldb_index) { 00174 $tablename = $xmldb_table->getName(); 00175 00177 if (!$this->table_exists($xmldb_table)) { 00178 throw new ddl_table_missing_exception($tablename); 00179 } 00180 00182 $indcolumns = $xmldb_index->getFields(); 00183 00185 $indexes = $this->mdb->get_indexes($tablename); 00186 00188 foreach ($indexes as $indexname => $index) { 00189 $columns = $index['columns']; 00191 $diferences = array_merge(array_diff($columns, $indcolumns), array_diff($indcolumns, $columns)); 00193 if (empty($diferences)) { 00194 return $indexname; 00195 } 00196 } 00197 00199 return false; 00200 } 00201 00209 public function index_exists(xmldb_table $xmldb_table, xmldb_index $xmldb_index) { 00210 if (!$this->table_exists($xmldb_table)) { 00211 return false; 00212 } 00213 return ($this->find_index_name($xmldb_table, $xmldb_index) !== false); 00214 } 00215 00228 public function find_check_constraint_name(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00229 00231 if (!$this->table_exists($xmldb_table)) { 00232 throw new ddl_table_missing_exception($xmldb_table->getName()); 00233 } 00234 00236 if (!$this->field_exists($xmldb_table, $xmldb_field)) { 00237 throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); 00238 } 00239 00241 $checks = false; 00242 if ($objchecks = $this->generator->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) { 00244 $objcheck = array_shift($objchecks); 00245 if ($objcheck) { 00246 $checks = strtolower($objcheck->name); 00247 } 00248 } 00249 00251 return $checks; 00252 } 00253 00263 public function check_constraint_exists(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00264 return ($this->find_check_constraint_name($xmldb_table, $xmldb_field) !== false); 00265 } 00266 00278 public function find_key_name(xmldb_table $xmldb_table, xmldb_key $xmldb_key) { 00279 00280 $keycolumns = $xmldb_key->getFields(); 00281 00292 00295 if ($this->generator->primary_key_name && $xmldb_key->getType() == XMLDB_KEY_PRIMARY) { 00296 return $this->generator->primary_key_name; 00297 } else { 00299 switch ($xmldb_key->getType()) { 00300 case XMLDB_KEY_PRIMARY: 00301 $suffix = 'pk'; 00302 break; 00303 case XMLDB_KEY_UNIQUE: 00304 $suffix = 'uk'; 00305 break; 00306 case XMLDB_KEY_FOREIGN_UNIQUE: 00307 case XMLDB_KEY_FOREIGN: 00308 $suffix = 'fk'; 00309 break; 00310 } 00312 return $this->generator->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), $suffix); 00313 } 00314 } 00315 00322 public function delete_tables_from_xmldb_file($file) { 00323 00324 $xmldb_file = new xmldb_file($file); 00325 00326 if (!$xmldb_file->fileExists()) { 00327 throw new ddl_exception('ddlxmlfileerror', null, 'File does not exist'); 00328 } 00329 00330 $loaded = $xmldb_file->loadXMLStructure(); 00331 $structure = $xmldb_file->getStructure(); 00332 00333 if (!$loaded || !$xmldb_file->isLoaded()) { 00335 if ($structure) { 00336 if ($errors = $structure->getAllErrors()) { 00337 throw new ddl_exception('ddlxmlfileerror', null, 'Errors found in XMLDB file: '. implode (', ', $errors)); 00338 } 00339 } 00340 throw new ddl_exception('ddlxmlfileerror', null, 'not loaded??'); 00341 } 00342 00343 if ($xmldb_tables = $structure->getTables()) { 00344 foreach($xmldb_tables as $table) { 00345 if ($this->table_exists($table)) { 00346 $this->drop_table($table); 00347 } 00348 } 00349 } 00350 } 00351 00360 public function drop_table(xmldb_table $xmldb_table) { 00362 if (!$this->table_exists($xmldb_table)) { 00363 throw new ddl_table_missing_exception($xmldb_table->getName()); 00364 } 00365 00366 if (!$sqlarr = $this->generator->getDropTableSQL($xmldb_table)) { 00367 throw new ddl_exception('ddlunknownerror', null, 'table drop sql not generated'); 00368 } 00369 00370 $this->execute_sql_arr($sqlarr); 00371 } 00372 00378 private function load_xmldb_file($file) { 00379 $xmldb_file = new xmldb_file($file); 00380 00381 if (!$xmldb_file->fileExists()) { 00382 throw new ddl_exception('ddlxmlfileerror', null, 'File does not exist'); 00383 } 00384 00385 $loaded = $xmldb_file->loadXMLStructure(); 00386 if (!$loaded || !$xmldb_file->isLoaded()) { 00388 if ($structure =& $xmldb_file->getStructure()) { 00389 if ($errors = $structure->getAllErrors()) { 00390 throw new ddl_exception('ddlxmlfileerror', null, 'Errors found in XMLDB file: '. implode (', ', $errors)); 00391 } 00392 } 00393 throw new ddl_exception('ddlxmlfileerror', null, 'not loaded??'); 00394 } 00395 00396 return $xmldb_file; 00397 } 00398 00405 public function install_from_xmldb_file($file) { 00406 $xmldb_file = $this->load_xmldb_file($file); 00407 $xmldb_structure = $xmldb_file->getStructure(); 00408 $this->install_from_xmldb_structure($xmldb_structure); 00409 } 00410 00419 public function install_one_table_from_xmldb_file($file, $tablename, $cachestructures = false) { 00420 00421 static $xmldbstructurecache = array(); // To store cached structures 00422 if (!empty($xmldbstructurecache) && array_key_exists($file, $xmldbstructurecache)) { 00423 $xmldb_structure = $xmldbstructurecache[$file]; 00424 } else { 00425 $xmldb_file = $this->load_xmldb_file($file); 00426 $xmldb_structure = $xmldb_file->getStructure(); 00427 if ($cachestructures) { 00428 $xmldbstructurecache[$file] = $xmldb_structure; 00429 } 00430 } 00431 00432 $targettable = $xmldb_structure->getTable($tablename); 00433 if (is_null($targettable)) { 00434 throw new ddl_exception('ddlunknowntable', null, 'The table ' . $tablename . ' is not defined in file ' . $file); 00435 } 00436 $targettable->setNext(NULL); 00437 $targettable->setPrevious(NULL); 00438 00439 $tempstructure = new xmldb_structure('temp'); 00440 $tempstructure->addTable($targettable); 00441 $this->install_from_xmldb_structure($tempstructure); 00442 } 00443 00451 public function install_from_xmldb_structure($xmldb_structure) { 00452 00453 if (!$sqlarr = $this->generator->getCreateStructureSQL($xmldb_structure)) { 00454 return; // nothing to do 00455 } 00456 $this->execute_sql_arr($sqlarr); 00457 } 00458 00466 public function create_table(xmldb_table $xmldb_table) { 00468 if ($this->table_exists($xmldb_table)) { 00469 throw new ddl_exception('ddltablealreadyexists', $xmldb_table->getName()); 00470 } 00471 00472 if (!$sqlarr = $this->generator->getCreateTableSQL($xmldb_table)) { 00473 throw new ddl_exception('ddlunknownerror', null, 'table create sql not generated'); 00474 } 00475 $this->execute_sql_arr($sqlarr); 00476 } 00477 00488 public function create_temp_table(xmldb_table $xmldb_table) { 00489 00490 // Check table doesn't exist 00491 if ($this->table_exists($xmldb_table)) { 00492 throw new ddl_exception('ddltablealreadyexists', $xmldb_table->getName()); 00493 } 00494 00495 if (!$sqlarr = $this->generator->getCreateTempTableSQL($xmldb_table)) { 00496 throw new ddl_exception('ddlunknownerror', null, 'temp table create sql not generated'); 00497 } 00498 00499 $this->execute_sql_arr($sqlarr); 00500 } 00501 00511 public function drop_temp_table(xmldb_table $xmldb_table) { 00512 00514 if (!$this->table_exists($xmldb_table)) { 00515 throw new ddl_table_missing_exception($xmldb_table->getName()); 00516 } 00517 00518 if (!$sqlarr = $this->generator->getDropTempTableSQL($xmldb_table)) { 00519 throw new ddl_exception('ddlunknownerror', null, 'temp table drop sql not generated'); 00520 } 00521 00522 $this->execute_sql_arr($sqlarr); 00523 } 00524 00533 public function rename_table(xmldb_table $xmldb_table, $newname) { 00535 if (!$newname) { 00536 throw new ddl_exception('ddlunknownerror', null, 'newname can not be empty'); 00537 } 00538 00539 $check = new xmldb_table($newname); 00540 00542 if (!$this->table_exists($xmldb_table)) { 00543 if ($this->table_exists($check)) { 00544 throw new ddl_exception('ddlunknownerror', null, 'table probably already renamed'); 00545 } else { 00546 throw new ddl_table_missing_exception($xmldb_table->getName()); 00547 } 00548 } 00549 00551 if ($this->table_exists($check)) { 00552 throw new ddl_exception('ddltablealreadyexists', $xmldb_table->getName(), 'can not rename table'); 00553 } 00554 00555 if (!$sqlarr = $this->generator->getRenameTableSQL($xmldb_table, $newname)) { 00556 throw new ddl_exception('ddlunknownerror', null, 'table rename sql not generated'); 00557 } 00558 00559 $this->execute_sql_arr($sqlarr); 00560 } 00561 00562 00570 public function add_field(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00572 if ($this->field_exists($xmldb_table, $xmldb_field)) { 00573 throw new ddl_exception('ddlfieldalreadyexists', $xmldb_field->getName()); 00574 } 00575 00578 if ($xmldb_field->getNotNull() && $this->generator->getDefaultValue($xmldb_field) === NULL && $this->mdb->count_records($xmldb_table->getName())) { 00579 throw new ddl_exception('ddlunknownerror', null, 'Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() . 00580 ' cannot be added. Not null fields added to non empty tables require default value. Create skipped'); 00581 } 00582 00583 if (!$sqlarr = $this->generator->getAddFieldSQL($xmldb_table, $xmldb_field)) { 00584 throw new ddl_exception('ddlunknownerror', null, 'addfield sql not generated'); 00585 } 00586 $this->execute_sql_arr($sqlarr); 00587 } 00588 00596 public function drop_field(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00597 if (!$this->table_exists($xmldb_table)) { 00598 throw new ddl_table_missing_exception($xmldb_table->getName()); 00599 } 00601 if (!$this->field_exists($xmldb_table, $xmldb_field)) { 00602 throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); 00603 } 00605 $this->check_field_dependencies($xmldb_table, $xmldb_field); 00606 00607 if (!$sqlarr = $this->generator->getDropFieldSQL($xmldb_table, $xmldb_field)) { 00608 throw new ddl_exception('ddlunknownerror', null, 'drop_field sql not generated'); 00609 } 00610 00611 $this->execute_sql_arr($sqlarr); 00612 } 00613 00621 public function change_field_type(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00622 if (!$this->table_exists($xmldb_table)) { 00623 throw new ddl_table_missing_exception($xmldb_table->getName()); 00624 } 00626 if (!$this->field_exists($xmldb_table, $xmldb_field)) { 00627 throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); 00628 } 00630 $this->check_field_dependencies($xmldb_table, $xmldb_field); 00631 00632 if (!$sqlarr = $this->generator->getAlterFieldSQL($xmldb_table, $xmldb_field)) { 00633 return; // probably nothing to do 00634 } 00635 00636 $this->execute_sql_arr($sqlarr); 00637 } 00638 00646 public function change_field_precision(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00648 $this->change_field_type($xmldb_table, $xmldb_field); 00649 } 00650 00658 public function change_field_unsigned(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00660 $this->change_field_type($xmldb_table, $xmldb_field); 00661 } 00662 00670 public function change_field_notnull(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00672 $this->change_field_type($xmldb_table, $xmldb_field); 00673 } 00674 00683 public function change_field_default(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00684 if (!$this->table_exists($xmldb_table)) { 00685 throw new ddl_table_missing_exception($xmldb_table->getName()); 00686 } 00688 if (!$this->field_exists($xmldb_table, $xmldb_field)) { 00689 throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); 00690 } 00692 $this->check_field_dependencies($xmldb_table, $xmldb_field); 00693 00694 if (!$sqlarr = $this->generator->getModifyDefaultSQL($xmldb_table, $xmldb_field)) { 00695 return; //Empty array = nothing to do = no error 00696 } 00697 00698 $this->execute_sql_arr($sqlarr); 00699 } 00700 00710 public function drop_enum_from_field(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00711 if (!$this->table_exists($xmldb_table)) { 00712 throw new ddl_table_missing_exception($xmldb_table->getName()); 00713 } 00715 if (!$this->field_exists($xmldb_table, $xmldb_field)) { 00716 throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); 00717 } 00718 00719 if (!$this->check_constraint_exists($xmldb_table, $xmldb_field)) { 00720 debugging('Enum for ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() . 00721 ' does not exist. Delete skipped', DEBUG_DEVELOPER); 00722 return; //Enum does not exist, nothing to delete 00723 } 00724 00725 if (!$sqlarr = $this->generator->getDropEnumSQL($xmldb_table, $xmldb_field)) { 00726 return; //Empty array = nothing to do = no error 00727 } 00728 00729 $this->execute_sql_arr($sqlarr); 00730 } 00731 00741 public function rename_field(xmldb_table $xmldb_table, xmldb_field $xmldb_field, $newname) { 00742 if (empty($newname)) { 00743 throw new ddl_exception('ddlunknownerror', null, 'newname can not be empty'); 00744 } 00745 00746 if (!$this->table_exists($xmldb_table)) { 00747 throw new ddl_table_missing_exception($xmldb_table->getName()); 00748 } 00749 00751 if (!$this->field_exists($xmldb_table, $xmldb_field)) { 00752 throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); 00753 } 00754 00756 if (!$xmldb_field->getType()) { 00757 throw new ddl_exception('ddlunknownerror', null, 00758 'Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() . 00759 ' must contain full specs. Rename skipped'); 00760 } 00761 00763 if ($xmldb_field->getName() == 'id') { 00764 throw new ddl_exception('ddlunknownerror', null, 00765 'Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() . 00766 ' cannot be renamed. Rename skipped'); 00767 } 00768 00769 if (!$sqlarr = $this->generator->getRenameFieldSQL($xmldb_table, $xmldb_field, $newname)) { 00770 return; //Empty array = nothing to do = no error 00771 } 00772 00773 $this->execute_sql_arr($sqlarr); 00774 } 00775 00781 private function check_field_dependencies(xmldb_table $xmldb_table, xmldb_field $xmldb_field) { 00782 00784 if (!$this->table_exists($xmldb_table)) { 00785 throw new ddl_table_missing_exception($xmldb_table->getName()); 00786 } 00787 00789 if (!$this->field_exists($xmldb_table, $xmldb_field)) { 00790 throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName()); 00791 } 00792 00794 if ($indexes = $this->mdb->get_indexes($xmldb_table->getName(), false)) { 00795 foreach ($indexes as $indexname => $index) { 00796 $columns = $index['columns']; 00797 if (in_array($xmldb_field->getName(), $columns)) { 00798 throw new ddl_dependency_exception('column', $xmldb_table->getName() . '->' . $xmldb_field->getName(), 00799 'index', $indexname . ' (' . implode(', ', $columns) . ')'); 00800 } 00801 } 00802 } 00803 } 00804 00812 public function add_key(xmldb_table $xmldb_table, xmldb_key $xmldb_key) { 00813 00814 if ($xmldb_key->getType() == XMLDB_KEY_PRIMARY) { // Prevent PRIMARY to be added (only in create table, being serious :-P) 00815 throw new ddl_exception('ddlunknownerror', null, 'Primary Keys can be added at table create time only'); 00816 } 00817 00818 if (!$sqlarr = $this->generator->getAddKeySQL($xmldb_table, $xmldb_key)) { 00819 return; //Empty array = nothing to do = no error 00820 } 00821 00822 $this->execute_sql_arr($sqlarr); 00823 } 00824 00832 public function drop_key(xmldb_table $xmldb_table, xmldb_key $xmldb_key) { 00833 if ($xmldb_key->getType() == XMLDB_KEY_PRIMARY) { // Prevent PRIMARY to be dropped (only in drop table, being serious :-P) 00834 throw new ddl_exception('ddlunknownerror', null, 'Primary Keys can be deleted at table drop time only'); 00835 } 00836 00837 if (!$sqlarr = $this->generator->getDropKeySQL($xmldb_table, $xmldb_key)) { 00838 return; //Empty array = nothing to do = no error 00839 } 00840 00841 $this->execute_sql_arr($sqlarr); 00842 } 00843 00853 public function rename_key(xmldb_table $xmldb_table, xmldb_key $xmldb_key, $newname) { 00854 debugging('rename_key() is one experimental feature. You must not use it in production!', DEBUG_DEVELOPER); 00855 00857 if (!$newname) { 00858 throw new ddl_exception('ddlunknownerror', null, 'newname can not be empty'); 00859 } 00860 00861 if (!$sqlarr = $this->generator->getRenameKeySQL($xmldb_table, $xmldb_key, $newname)) { 00862 throw new ddl_exception('ddlunknownerror', null, 'Some DBs do not support key renaming (MySQL, PostgreSQL, MsSQL). Rename skipped'); 00863 } 00864 00865 $this->execute_sql_arr($sqlarr); 00866 } 00867 00876 public function add_index($xmldb_table, $xmldb_intex) { 00877 if (!$this->table_exists($xmldb_table)) { 00878 throw new ddl_table_missing_exception($xmldb_table->getName()); 00879 } 00880 00882 if ($this->index_exists($xmldb_table, $xmldb_intex)) { 00883 throw new ddl_exception('ddlunknownerror', null, 00884 'Index ' . $xmldb_table->getName() . '->' . $xmldb_intex->getName() . 00885 ' already exists. Create skipped'); 00886 } 00887 00888 if (!$sqlarr = $this->generator->getAddIndexSQL($xmldb_table, $xmldb_intex)) { 00889 throw new ddl_exception('ddlunknownerror', null, 'add_index sql not generated'); 00890 } 00891 00892 $this->execute_sql_arr($sqlarr); 00893 } 00894 00903 public function drop_index($xmldb_table, $xmldb_intex) { 00904 if (!$this->table_exists($xmldb_table)) { 00905 throw new ddl_table_missing_exception($xmldb_table->getName()); 00906 } 00907 00909 if (!$this->index_exists($xmldb_table, $xmldb_intex)) { 00910 throw new ddl_exception('ddlunknownerror', null, 00911 'Index ' . $xmldb_table->getName() . '->' . $xmldb_intex->getName() . 00912 ' does not exist. Drop skipped'); 00913 } 00914 00915 if (!$sqlarr = $this->generator->getDropIndexSQL($xmldb_table, $xmldb_intex)) { 00916 throw new ddl_exception('ddlunknownerror', null, 'drop_index sql not generated'); 00917 } 00918 00919 $this->execute_sql_arr($sqlarr); 00920 } 00921 00932 public function rename_index($xmldb_table, $xmldb_intex, $newname) { 00933 debugging('rename_index() is one experimental feature. You must not use it in production!', DEBUG_DEVELOPER); 00934 00936 if (!$newname) { 00937 throw new ddl_exception('ddlunknownerror', null, 'newname can not be empty'); 00938 } 00939 00941 if (!$this->index_exists($xmldb_table, $xmldb_intex)) { 00942 throw new ddl_exception('ddlunknownerror', null, 00943 'Index ' . $xmldb_table->getName() . '->' . $xmldb_intex->getName() . 00944 ' does not exist. Rename skipped'); 00945 } 00946 00947 if (!$sqlarr = $this->generator->getRenameIndexSQL($xmldb_table, $xmldb_intex, $newname)) { 00948 throw new ddl_exception('ddlunknownerror', null, 'Some DBs do not support index renaming (MySQL). Rename skipped'); 00949 } 00950 00951 $this->execute_sql_arr($sqlarr); 00952 } 00953 00959 public function get_install_xml_schema() { 00960 global $CFG; 00961 require_once($CFG->libdir.'/adminlib.php'); 00962 00963 $schema = new xmldb_structure('export'); 00964 $schema->setVersion($CFG->version); 00965 $dbdirs = get_db_directories(); 00966 foreach ($dbdirs as $dbdir) { 00967 $xmldb_file = new xmldb_file($dbdir.'/install.xml'); 00968 if (!$xmldb_file->fileExists() or !$xmldb_file->loadXMLStructure()) { 00969 continue; 00970 } 00971 $structure = $xmldb_file->getStructure(); 00972 $tables = $structure->getTables(); 00973 foreach ($tables as $table) { 00974 $table->setPrevious(null); 00975 $table->setNext(null); 00976 $schema->addTable($table); 00977 } 00978 } 00979 return $schema; 00980 } 00981 00987 public function check_database_schema(xmldb_structure $schema) { 00988 $errors = array(); 00989 00990 $dbtables = $this->mdb->get_tables(); 00991 $tables = $schema->getTables(); 00992 00993 //TODO: maybe add several levels error/warning 00994 00995 // make sure that current and schema tables match exactly 00996 foreach ($tables as $table) { 00997 $tablename = $table->getName(); 00998 if (empty($dbtables[$tablename])) { 00999 if (!isset($errors[$tablename])) { 01000 $errors[$tablename] = array(); 01001 } 01002 $errors[$tablename][] = "Table $tablename is missing in database."; //TODO: localize 01003 continue; 01004 } 01005 01006 // a) check for required fields 01007 $dbfields = $this->mdb->get_columns($tablename); 01008 $fields = $table->getFields(); 01009 foreach ($fields as $field) { 01010 $fieldname = $field->getName(); 01011 if (empty($dbfields[$fieldname])) { 01012 if (!isset($errors[$tablename])) { 01013 $errors[$tablename] = array(); 01014 } 01015 $errors[$tablename][] = "Field $fieldname is missing in table $tablename."; //TODO: localize 01016 } 01017 unset($dbfields[$fieldname]); 01018 } 01019 01020 // b) check for extra fields (indicates unsupported hacks) - modify install.xml if you want the script to continue ;-) 01021 foreach ($dbfields as $fieldname=>$info) { 01022 if (!isset($errors[$tablename])) { 01023 $errors[$tablename] = array(); 01024 } 01025 $errors[$tablename][] = "Field $fieldname is not expected in table $tablename."; //TODO: localize 01026 } 01027 unset($dbtables[$tablename]); 01028 } 01029 01030 // look for unsupported tables - local custom tables should be in /local/xxxx/db/install.xml ;-) 01031 // if there is no prefix, we can not say if tale is ours :-( 01032 if ($this->generator->prefix !== '') { 01033 foreach ($dbtables as $tablename=>$unused) { 01034 if (strpos($tablename, 'pma_') === 0) { 01035 // ignore phpmyadmin tables for now 01036 continue; 01037 } 01038 if (strpos($tablename, 'test') === 0) { 01039 // ignore broken results of unit tests 01040 continue; 01041 } 01042 if (!isset($errors[$tablename])) { 01043 $errors[$tablename] = array(); 01044 } 01045 $errors[$tablename][] = "Table $tablename is not expected."; //TODO: localize 01046 } 01047 } 01048 01049 return $errors; 01050 } 01051 }