PageRenderTime 51ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ddllib.php

https://bitbucket.org/ceu/moodle_demo
PHP | 1563 lines | 805 code | 273 blank | 485 comment | 190 complexity | 8ecc5d1ce5703aa9034e6b9b047d145b MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php // $Id: ddllib.php,v 1.59.2.5 2011/08/03 16:28:19 moodlerobot Exp $
  2. ///////////////////////////////////////////////////////////////////////////
  3. // //
  4. // NOTICE OF COPYRIGHT //
  5. // //
  6. // Moodle - Modular Object-Oriented Dynamic Learning Environment //
  7. // http://moodle.com //
  8. // //
  9. // Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
  10. // (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
  11. // //
  12. // This program is free software; you can redistribute it and/or modify //
  13. // it under the terms of the GNU General Public License as published by //
  14. // the Free Software Foundation; either version 2 of the License, or //
  15. // (at your option) any later version. //
  16. // //
  17. // This program is distributed in the hope that it will be useful, //
  18. // but WITHOUT ANY WARRANTY; without even the implied warranty of //
  19. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
  20. // GNU General Public License for more details: //
  21. // //
  22. // http://www.gnu.org/copyleft/gpl.html //
  23. // //
  24. ///////////////////////////////////////////////////////////////////////////
  25. // This library includes all the required functions used to handle the DB
  26. // structure (DDL) independently of the underlying RDBMS in use. All the functions
  27. // rely on the XMLDBDriver classes to be able to generate the correct SQL
  28. // syntax needed by each DB.
  29. //
  30. // To define any structure to be created we'll use the schema defined
  31. // by the XMLDB classes, for tables, fields, indexes, keys and other
  32. // statements instead of direct handling of SQL sentences.
  33. //
  34. // This library should be used, exclusively, by the installation and
  35. // upgrade process of Moodle.
  36. //
  37. // For further documentation, visit http://docs.moodle.org/19/en/DDL_functions
  38. /// Add required XMLDB constants
  39. require_once($CFG->libdir . '/xmldb/classes/XMLDBConstants.php');
  40. /// Add main XMLDB Generator
  41. require_once($CFG->libdir . '/xmldb/classes/generators/XMLDBGenerator.class.php');
  42. /// Add required XMLDB DB classes
  43. require_once($CFG->libdir . '/xmldb/classes/XMLDBObject.class.php');
  44. require_once($CFG->libdir . '/xmldb/classes/XMLDBFile.class.php');
  45. require_once($CFG->libdir . '/xmldb/classes/XMLDBStructure.class.php');
  46. require_once($CFG->libdir . '/xmldb/classes/XMLDBTable.class.php');
  47. require_once($CFG->libdir . '/xmldb/classes/XMLDBField.class.php');
  48. require_once($CFG->libdir . '/xmldb/classes/XMLDBKey.class.php');
  49. require_once($CFG->libdir . '/xmldb/classes/XMLDBIndex.class.php');
  50. require_once($CFG->libdir . '/xmldb/classes/XMLDBStatement.class.php');
  51. /// Based on $CFG->dbtype, add the proper generator class
  52. if (!file_exists($CFG->libdir . '/xmldb/classes/generators/' . $CFG->dbtype . '/' . $CFG->dbtype . '.class.php')) {
  53. error ('DB Type: ' . $CFG->dbtype . ' not supported by XMLDB');
  54. }
  55. require_once($CFG->libdir . '/xmldb/classes/generators/' . $CFG->dbtype . '/' . $CFG->dbtype . '.class.php');
  56. /// Add other libraries
  57. require_once($CFG->libdir . '/xmlize.php');
  58. /**
  59. * Add a new field to a table, or modify an existing one (if oldfield is defined).
  60. *
  61. * WARNING: This function is deprecated and will be removed in future versions.
  62. * Please use XMLDB (see http://docs.moodle.org/dev/DDL_functions ).
  63. *
  64. * Warning: Please be careful on primary keys, as this function will eat auto_increments
  65. *
  66. * @uses $CFG
  67. * @uses $db
  68. * @param string $table the name of the table to modify. (Without the prefix.)
  69. * @param string $oldfield If changing an existing column, the name of that column.
  70. * @param string $field The name of the column at the end of the operation.
  71. * @param string $type The type of the column at the end of the operation. TEXT, VARCHAR, CHAR, INTEGER, REAL, or TINYINT
  72. * @param string $size The size of that column type. As in VARCHAR($size), or INTEGER($size).
  73. * @param string $signed For numeric column types, whether that column is 'signed' or 'unsigned'.
  74. * @param string $default The new default value for the column.
  75. * @param string $null 'not null', or '' to allow nulls.
  76. * @param string $after Which column to insert this one after. Not supported on Postgres.
  77. *
  78. * @return boolean Wheter the operation succeeded.
  79. */
  80. function table_column($table, $oldfield, $field, $type='integer', $size='10',
  81. $signed='unsigned', $default='0', $null='not null', $after='') {
  82. global $CFG, $db, $empty_rs_cache;
  83. if (!empty($empty_rs_cache[$table])) { // Clear the recordset cache because it's out of date
  84. unset($empty_rs_cache[$table]);
  85. }
  86. switch (strtolower($CFG->dbtype)) {
  87. case 'mysql':
  88. case 'mysqlt':
  89. switch (strtolower($type)) {
  90. case 'text':
  91. $type = 'TEXT';
  92. $signed = '';
  93. break;
  94. case 'integer':
  95. $type = 'INTEGER('. $size .')';
  96. break;
  97. case 'varchar':
  98. $type = 'VARCHAR('. $size .')';
  99. $signed = '';
  100. break;
  101. case 'char':
  102. $type = 'CHAR('. $size .')';
  103. $signed = '';
  104. break;
  105. }
  106. if (!empty($oldfield)) {
  107. $operation = 'CHANGE '. $oldfield .' '. $field;
  108. } else {
  109. $operation = 'ADD '. $field;
  110. }
  111. $default = 'DEFAULT \''. $default .'\'';
  112. if (!empty($after)) {
  113. $after = 'AFTER `'. $after .'`';
  114. }
  115. return execute_sql('ALTER TABLE '. $CFG->prefix . $table .' '. $operation .' '. $type .' '. $signed .' '. $default .' '. $null .' '. $after);
  116. case 'postgres7': // From Petri Asikainen
  117. //Check db-version
  118. $dbinfo = $db->ServerInfo();
  119. $dbver = substr($dbinfo['version'],0,3);
  120. //to prevent conflicts with reserved words
  121. $realfield = '"'. $field .'"';
  122. $field = '"'. $field .'_alter_column_tmp"';
  123. $oldfield = '"'. $oldfield .'"';
  124. switch (strtolower($type)) {
  125. case 'tinyint':
  126. case 'integer':
  127. if ($size <= 4) {
  128. $type = 'INT2';
  129. }
  130. if ($size <= 10) {
  131. $type = 'INT';
  132. }
  133. if ($size > 10) {
  134. $type = 'INT8';
  135. }
  136. break;
  137. case 'varchar':
  138. $type = 'VARCHAR('. $size .')';
  139. break;
  140. case 'char':
  141. $type = 'CHAR('. $size .')';
  142. $signed = '';
  143. break;
  144. }
  145. $default = '\''. $default .'\'';
  146. //After is not implemented in postgesql
  147. //if (!empty($after)) {
  148. // $after = "AFTER '$after'";
  149. //}
  150. //Use transactions
  151. execute_sql('BEGIN');
  152. //Always use temporary column
  153. execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ADD COLUMN '. $field .' '. $type);
  154. //Add default values
  155. execute_sql('UPDATE '. $CFG->prefix . $table .' SET '. $field .'='. $default);
  156. if ($dbver >= '7.3') {
  157. // modifying 'not null' is posible before 7.3
  158. //update default values to table
  159. if (strtoupper($null) == 'NOT NULL') {
  160. execute_sql('UPDATE '. $CFG->prefix . $table .' SET '. $field .'='. $default .' WHERE '. $field .' IS NULL');
  161. execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' SET '. $null);
  162. } else {
  163. execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' DROP NOT NULL');
  164. }
  165. }
  166. execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' SET DEFAULT '. $default);
  167. if ( $oldfield != '""' ) {
  168. // We are changing the type of a column. This may require doing some casts...
  169. $casting = '';
  170. $oldtype = column_type($table, $oldfield);
  171. $newtype = column_type($table, $field);
  172. // Do we need a cast?
  173. if($newtype == 'N' && $oldtype == 'C') {
  174. $casting = 'CAST(CAST('.$oldfield.' AS TEXT) AS REAL)';
  175. }
  176. else if($newtype == 'I' && $oldtype == 'C') {
  177. $casting = 'CAST(CAST('.$oldfield.' AS TEXT) AS INTEGER)';
  178. }
  179. else {
  180. $casting = $oldfield;
  181. }
  182. // Run the update query, casting as necessary
  183. execute_sql('UPDATE '. $CFG->prefix . $table .' SET '. $field .' = '. $casting);
  184. execute_sql('ALTER TABLE '. $CFG->prefix . $table .' DROP COLUMN '. $oldfield);
  185. }
  186. execute_sql('ALTER TABLE '. $CFG->prefix . $table .' RENAME COLUMN '. $field .' TO '. $realfield);
  187. return execute_sql('COMMIT');
  188. default:
  189. switch (strtolower($type)) {
  190. case 'integer':
  191. $type = 'INTEGER';
  192. break;
  193. case 'varchar':
  194. $type = 'VARCHAR';
  195. break;
  196. }
  197. $default = 'DEFAULT \''. $default .'\'';
  198. if (!empty($after)) {
  199. $after = 'AFTER '. $after;
  200. }
  201. if (!empty($oldfield)) {
  202. execute_sql('ALTER TABLE '. $CFG->prefix . $table .' RENAME COLUMN '. $oldfield .' '. $field);
  203. } else {
  204. execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ADD COLUMN '. $field .' '. $type);
  205. }
  206. execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' SET '. $null);
  207. return execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' SET '. $default);
  208. }
  209. }
  210. /**
  211. * Given one XMLDBTable, check if it exists in DB (true/false)
  212. *
  213. * @param XMLDBTable table to be searched for
  214. * @return boolean true/false
  215. */
  216. function table_exists($table) {
  217. global $CFG, $db;
  218. $exists = true;
  219. /// Do this function silenty (to avoid output in install/upgrade process)
  220. $olddbdebug = $db->debug;
  221. $db->debug = false;
  222. /// Load the needed generator
  223. $classname = 'XMLDB' . $CFG->dbtype;
  224. $generator = new $classname();
  225. $generator->setPrefix($CFG->prefix);
  226. /// Calculate the name of the table
  227. $tablename = $generator->getTableName($table, false);
  228. /// Search such tablename in DB
  229. $metatables = $db->MetaTables();
  230. $metatables = array_flip($metatables);
  231. $metatables = array_change_key_case($metatables, CASE_LOWER);
  232. if (!array_key_exists($tablename, $metatables)) {
  233. $exists = false;
  234. }
  235. /// Re-set original debug
  236. $db->debug = $olddbdebug;
  237. return $exists;
  238. }
  239. /**
  240. * Given one XMLDBField, check if it exists in DB (true/false)
  241. *
  242. * @uses, $db
  243. * @param XMLDBTable the table
  244. * @param XMLDBField the field to be searched for
  245. * @return boolean true/false
  246. */
  247. function field_exists($table, $field) {
  248. global $CFG, $db;
  249. $exists = true;
  250. /// Do this function silenty (to avoid output in install/upgrade process)
  251. $olddbdebug = $db->debug;
  252. $db->debug = false;
  253. /// Check the table exists
  254. if (!table_exists($table)) {
  255. $db->debug = $olddbdebug; //Re-set original $db->debug
  256. return false;
  257. }
  258. /// Load the needed generator
  259. $classname = 'XMLDB' . $CFG->dbtype;
  260. $generator = new $classname();
  261. $generator->setPrefix($CFG->prefix);
  262. /// Calculate the name of the table
  263. $tablename = $generator->getTableName($table, false);
  264. /// Get list of fields in table
  265. $fields = null;
  266. if ($fields = $db->MetaColumns($tablename)) {
  267. $fields = array_change_key_case($fields, CASE_LOWER);
  268. }
  269. if (!array_key_exists($field->getName(), $fields)) {
  270. $exists = false;
  271. }
  272. /// Re-set original debug
  273. $db->debug = $olddbdebug;
  274. return $exists;
  275. }
  276. /**
  277. * Given one XMLDBIndex, check if it exists in DB (true/false)
  278. *
  279. * @uses, $db
  280. * @param XMLDBTable the table
  281. * @param XMLDBIndex the index to be searched for
  282. * @return boolean true/false
  283. */
  284. function index_exists($table, $index) {
  285. global $CFG, $db;
  286. $exists = true;
  287. /// Do this function silenty (to avoid output in install/upgrade process)
  288. $olddbdebug = $db->debug;
  289. $db->debug = false;
  290. /// Wrap over find_index_name to see if the index exists
  291. if (!find_index_name($table, $index)) {
  292. $exists = false;
  293. }
  294. /// Re-set original debug
  295. $db->debug = $olddbdebug;
  296. return $exists;
  297. }
  298. /**
  299. * Given one XMLDBField, check if it has a check constraint in DB
  300. *
  301. * @uses, $db
  302. * @param XMLDBTable the table
  303. * @param XMLDBField the field to be searched for any existing constraint
  304. * @return boolean true/false
  305. */
  306. function check_constraint_exists($table, $field) {
  307. global $CFG, $db;
  308. $exists = true;
  309. /// Do this function silenty (to avoid output in install/upgrade process)
  310. $olddbdebug = $db->debug;
  311. $db->debug = false;
  312. /// Wrap over find_check_constraint_name to see if the index exists
  313. if (!find_check_constraint_name($table, $field)) {
  314. $exists = false;
  315. }
  316. /// Re-set original debug
  317. $db->debug = $olddbdebug;
  318. return $exists;
  319. }
  320. /**
  321. * This function IS NOT IMPLEMENTED. ONCE WE'LL BE USING RELATIONAL
  322. * INTEGRITY IT WILL BECOME MORE USEFUL. FOR NOW, JUST CALCULATE "OFFICIAL"
  323. * KEY NAMES WITHOUT ACCESSING TO DB AT ALL.
  324. * Given one XMLDBKey, the function returns the name of the key in DB (if exists)
  325. * of false if it doesn't exist
  326. *
  327. * @uses, $db
  328. * @param XMLDBTable the table to be searched
  329. * @param XMLDBKey the key to be searched
  330. * @return string key name of false
  331. */
  332. function find_key_name($table, $xmldb_key) {
  333. global $CFG, $db;
  334. /// Extract key columns
  335. $keycolumns = $xmldb_key->getFields();
  336. /// Get list of keys in table
  337. /// first primaries (we aren't going to use this now, because the MetaPrimaryKeys is awful)
  338. ///TODO: To implement when we advance in relational integrity
  339. /// then uniques (note that Moodle, for now, shouldn't have any UNIQUE KEY for now, but unique indexes)
  340. ///TODO: To implement when we advance in relational integrity (note that AdoDB hasn't any MetaXXX for this.
  341. /// then foreign (note that Moodle, for now, shouldn't have any FOREIGN KEY for now, but indexes)
  342. ///TODO: To implement when we advance in relational integrity (note that AdoDB has one MetaForeignKeys()
  343. ///but it's far from perfect.
  344. /// TODO: To create the proper functions inside each generator to retrieve all the needed KEY info (name
  345. /// columns, reftable and refcolumns
  346. /// So all we do is to return the official name of the requested key without any confirmation!)
  347. $classname = 'XMLDB' . $CFG->dbtype;
  348. $generator = new $classname();
  349. $generator->setPrefix($CFG->prefix);
  350. /// One exception, harcoded primary constraint names
  351. if ($generator->primary_key_name && $xmldb_key->getType() == XMLDB_KEY_PRIMARY) {
  352. return $generator->primary_key_name;
  353. } else {
  354. /// Calculate the name suffix
  355. switch ($xmldb_key->getType()) {
  356. case XMLDB_KEY_PRIMARY:
  357. $suffix = 'pk';
  358. break;
  359. case XMLDB_KEY_UNIQUE:
  360. $suffix = 'uk';
  361. break;
  362. case XMLDB_KEY_FOREIGN_UNIQUE:
  363. case XMLDB_KEY_FOREIGN:
  364. $suffix = 'fk';
  365. break;
  366. }
  367. /// And simply, return the oficial name
  368. return $generator->getNameForObject($table->getName(), implode(', ', $xmldb_key->getFields()), $suffix);
  369. }
  370. }
  371. /**
  372. * Given one XMLDBIndex, the function returns the name of the index in DB (if exists)
  373. * of false if it doesn't exist
  374. *
  375. * @uses, $db
  376. * @param XMLDBTable the table to be searched
  377. * @param XMLDBIndex the index to be searched
  378. * @return string index name of false
  379. */
  380. function find_index_name($table, $index) {
  381. global $CFG, $db;
  382. /// Do this function silenty (to avoid output in install/upgrade process)
  383. $olddbdebug = $db->debug;
  384. $db->debug = false;
  385. /// Extract index columns
  386. $indcolumns = $index->getFields();
  387. /// Check the table exists
  388. if (!table_exists($table)) {
  389. $db->debug = $olddbdebug; //Re-set original $db->debug
  390. return false;
  391. }
  392. /// Load the needed generator
  393. $classname = 'XMLDB' . $CFG->dbtype;
  394. $generator = new $classname();
  395. $generator->setPrefix($CFG->prefix);
  396. /// Calculate the name of the table
  397. $tablename = $generator->getTableName($table, false);
  398. /// Get list of indexes in table
  399. $indexes = null;
  400. if ($indexes = $db->MetaIndexes($tablename)) {
  401. $indexes = array_change_key_case($indexes, CASE_LOWER);
  402. }
  403. /// Iterate over them looking for columns coincidence
  404. if ($indexes) {
  405. foreach ($indexes as $indexname => $index) {
  406. $columns = $index['columns'];
  407. /// Lower case column names
  408. $columns = array_flip($columns);
  409. $columns = array_change_key_case($columns, CASE_LOWER);
  410. $columns = array_flip($columns);
  411. /// Check if index matchs queried index
  412. $diferences = array_merge(array_diff($columns, $indcolumns), array_diff($indcolumns, $columns));
  413. /// If no diferences, we have find the index
  414. if (empty($diferences)) {
  415. $db->debug = $olddbdebug; //Re-set original $db->debug
  416. return $indexname;
  417. }
  418. }
  419. }
  420. /// Arriving here, index not found
  421. $db->debug = $olddbdebug; //Re-set original $db->debug
  422. return false;
  423. }
  424. /**
  425. * Given one XMLDBField, the function returns the name of the check constraint in DB (if exists)
  426. * of false if it doesn't exist. Note that XMLDB limits the number of check constrainst per field
  427. * to 1 "enum-like" constraint. So, if more than one is returned, only the first one will be
  428. * retrieved by this funcion.
  429. *
  430. * @uses, $db
  431. * @param XMLDBTable the table to be searched
  432. * @param XMLDBField the field to be searched
  433. * @return string check consrtaint name or false
  434. */
  435. function find_check_constraint_name($table, $field) {
  436. global $CFG, $db;
  437. /// Do this function silenty (to avoid output in install/upgrade process)
  438. $olddbdebug = $db->debug;
  439. $db->debug = false;
  440. /// Check the table exists
  441. if (!table_exists($table)) {
  442. $db->debug = $olddbdebug; //Re-set original $db->debug
  443. return false;
  444. }
  445. /// Check the field exists
  446. if (!field_exists($table, $field)) {
  447. $db->debug = $olddbdebug; //Re-set original $db->debug
  448. return false;
  449. }
  450. /// Load the needed generator
  451. $classname = 'XMLDB' . $CFG->dbtype;
  452. $generator = new $classname();
  453. $generator->setPrefix($CFG->prefix);
  454. /// Calculate the name of the table
  455. $tablename = $generator->getTableName($table, false);
  456. /// Get list of check_constraints in table/field
  457. $checks = null;
  458. if ($objchecks = $generator->getCheckConstraintsFromDB($table, $field)) {
  459. /// Get only the 1st element. Shouldn't be more than 1 under XMLDB
  460. $objcheck = array_shift($objchecks);
  461. if ($objcheck) {
  462. $checks = strtolower($objcheck->name);
  463. }
  464. }
  465. /// Arriving here, check not found
  466. $db->debug = $olddbdebug; //Re-set original $db->debug
  467. return $checks;
  468. }
  469. /**
  470. * Given one XMLDBTable, the function returns the name of its sequence in DB (if exists)
  471. * of false if it doesn't exist
  472. *
  473. * @param XMLDBTable the table to be searched
  474. * @return string sequence name of false
  475. */
  476. function find_sequence_name($table) {
  477. global $CFG, $db;
  478. $sequencename = false;
  479. /// Do this function silenty (to avoid output in install/upgrade process)
  480. $olddbdebug = $db->debug;
  481. $db->debug = false;
  482. if (strtolower(get_class($table)) != 'xmldbtable') {
  483. $db->debug = $olddbdebug; //Re-set original $db->debug
  484. return false;
  485. }
  486. /// Check table exists
  487. if (!table_exists($table)) {
  488. debugging('Table ' . $table->getName() .
  489. ' does not exist. Sequence not found', DEBUG_DEVELOPER);
  490. $db->debug = $olddbdebug; //Re-set original $db->debug
  491. return false; //Table doesn't exist, nothing to do
  492. }
  493. $sequencename = $table->getSequenceFromDB($CFG->dbtype, $CFG->prefix);
  494. $db->debug = $olddbdebug; //Re-set original $db->debug
  495. return $sequencename;
  496. }
  497. /**
  498. * This function will load one entire XMLDB file, generating all the needed
  499. * SQL statements, specific for each RDBMS ($CFG->dbtype) and, finally, it
  500. * will execute all those statements against the DB.
  501. *
  502. * @uses $CFG, $db
  503. * @param $file full path to the XML file to be used
  504. * @return boolean (true on success, false on error)
  505. */
  506. function install_from_xmldb_file($file) {
  507. global $CFG, $db;
  508. $status = true;
  509. $xmldb_file = new XMLDBFile($file);
  510. if (!$xmldb_file->fileExists()) {
  511. return false;
  512. }
  513. $loaded = $xmldb_file->loadXMLStructure();
  514. if (!$loaded || !$xmldb_file->isLoaded()) {
  515. /// Show info about the error if we can find it
  516. if ($structure =& $xmldb_file->getStructure()) {
  517. if ($errors = $structure->getAllErrors()) {
  518. notify('Errors found in XMLDB file: '. implode (', ', $errors));
  519. }
  520. }
  521. return false;
  522. }
  523. $structure = $xmldb_file->getStructure();
  524. if (!$sqlarr = $structure->getCreateStructureSQL($CFG->dbtype, $CFG->prefix, false)) {
  525. return true; //Empty array = nothing to do = no error
  526. }
  527. return execute_sql_arr($sqlarr);
  528. }
  529. /**
  530. * This function will all tables found in XMLDB file from db
  531. *
  532. * @uses $CFG, $db
  533. * @param $file full path to the XML file to be used
  534. * @param $feedback
  535. * @return boolean (true on success, false on error)
  536. */
  537. function delete_tables_from_xmldb_file($file, $feedback=true ) {
  538. global $CFG, $db;
  539. $status = true;
  540. $xmldb_file = new XMLDBFile($file);
  541. if (!$xmldb_file->fileExists()) {
  542. return false;
  543. }
  544. $loaded = $xmldb_file->loadXMLStructure();
  545. $structure =& $xmldb_file->getStructure();
  546. if (!$loaded || !$xmldb_file->isLoaded()) {
  547. /// Show info about the error if we can find it
  548. if ($feedback and $structure) {
  549. if ($errors = $structure->getAllErrors()) {
  550. notify('Errors found in XMLDB file: '. implode (', ', $errors));
  551. }
  552. }
  553. return false;
  554. }
  555. if ($tables = $structure->getTables()) {
  556. foreach($tables as $table) {
  557. if (table_exists($table)) {
  558. drop_table($table, true, $feedback);
  559. }
  560. }
  561. }
  562. return true;
  563. }
  564. /**
  565. * Delete all plugin tables
  566. * @name string name of plugin, used as table prefix
  567. * @file string path to install.xml file
  568. * @feedback boolean
  569. */
  570. function drop_plugin_tables($name, $file, $feedback=true) {
  571. global $CFG, $db;
  572. // first try normal delete
  573. if (delete_tables_from_xmldb_file($file, $feedback)) {
  574. return true;
  575. }
  576. // then try to find all tables that start with name and are not in any xml file
  577. $used_tables = get_used_table_names();
  578. $tables = $db->MetaTables();
  579. /// Iterate over, fixing id fields as necessary
  580. foreach ($tables as $table) {
  581. if (strlen($CFG->prefix)) {
  582. if (strpos($table, $CFG->prefix) !== 0) {
  583. continue;
  584. }
  585. $table = substr($table, strlen($CFG->prefix));
  586. }
  587. $table = strtolower($table);
  588. if (strpos($table, $name) !== 0) {
  589. continue;
  590. }
  591. if (in_array($table, $used_tables)) {
  592. continue;
  593. }
  594. // found orphan table --> delete it
  595. $table = new XMLDBTable($table);
  596. if (table_exists($table)) {
  597. drop_table($table, true, $feedback);
  598. }
  599. }
  600. return true;
  601. }
  602. /**
  603. * Returns names of all known tables == tables that moodle knowns about.
  604. * @return array of lowercase table names
  605. */
  606. function get_used_table_names() {
  607. $table_names = array();
  608. $dbdirs = get_db_directories();
  609. foreach ($dbdirs as $dbdir) {
  610. $file = $dbdir.'/install.xml';
  611. $xmldb_file = new XMLDBFile($file);
  612. if (!$xmldb_file->fileExists()) {
  613. continue;
  614. }
  615. $loaded = $xmldb_file->loadXMLStructure();
  616. $structure =& $xmldb_file->getStructure();
  617. if ($loaded and $tables = $structure->getTables()) {
  618. foreach($tables as $table) {
  619. $table_names[] = strtolower($table->name);
  620. }
  621. }
  622. }
  623. return $table_names;
  624. }
  625. /**
  626. * Returns list of all directories where we expect install.xml files
  627. * @return array of paths
  628. */
  629. function get_db_directories() {
  630. global $CFG;
  631. $dbdirs = array();
  632. /// First, the main one (lib/db)
  633. $dbdirs[] = $CFG->libdir.'/db';
  634. /// Now, activity modules (mod/xxx/db)
  635. if ($plugins = get_list_of_plugins('mod')) {
  636. foreach ($plugins as $plugin) {
  637. $dbdirs[] = $CFG->dirroot.'/mod/'.$plugin.'/db';
  638. }
  639. }
  640. /// Now, assignment submodules (mod/assignment/type/xxx/db)
  641. if ($plugins = get_list_of_plugins('mod/assignment/type')) {
  642. foreach ($plugins as $plugin) {
  643. $dbdirs[] = $CFG->dirroot.'/mod/assignment/type/'.$plugin.'/db';
  644. }
  645. }
  646. /// Now, question types (question/type/xxx/db)
  647. if ($plugins = get_list_of_plugins('question/type')) {
  648. foreach ($plugins as $plugin) {
  649. $dbdirs[] = $CFG->dirroot.'/question/type/'.$plugin.'/db';
  650. }
  651. }
  652. /// Now, backup/restore stuff (backup/db)
  653. $dbdirs[] = $CFG->dirroot.'/backup/db';
  654. /// Now, block system stuff (blocks/db)
  655. $dbdirs[] = $CFG->dirroot.'/blocks/db';
  656. /// Now, blocks (blocks/xxx/db)
  657. if ($plugins = get_list_of_plugins('blocks', 'db')) {
  658. foreach ($plugins as $plugin) {
  659. $dbdirs[] = $CFG->dirroot.'/blocks/'.$plugin.'/db';
  660. }
  661. }
  662. /// Now, course formats (course/format/xxx/db)
  663. if ($plugins = get_list_of_plugins('course/format', 'db')) {
  664. foreach ($plugins as $plugin) {
  665. $dbdirs[] = $CFG->dirroot.'/course/format/'.$plugin.'/db';
  666. }
  667. }
  668. /// Now, enrolment plugins (enrol/xxx/db)
  669. if ($plugins = get_list_of_plugins('enrol', 'db')) {
  670. foreach ($plugins as $plugin) {
  671. $dbdirs[] = $CFG->dirroot.'/enrol/'.$plugin.'/db';
  672. }
  673. }
  674. /// Now admin report plugins (admin/report/xxx/db)
  675. if ($plugins = get_list_of_plugins($CFG->admin.'/report', 'db')) {
  676. foreach ($plugins as $plugin) {
  677. $dbdirs[] = $CFG->dirroot.'/'.$CFG->admin.'/report/'.$plugin.'/db';
  678. }
  679. }
  680. /// Local database changes, if the local folder exists.
  681. if (file_exists($CFG->dirroot . '/local')) {
  682. $dbdirs[] = $CFG->dirroot.'/local/db';
  683. }
  684. return $dbdirs;
  685. }
  686. /**
  687. * This function will create the table passed as argument with all its
  688. * fields/keys/indexes/sequences, everything based in the XMLDB object
  689. *
  690. * @uses $CFG, $db
  691. * @param XMLDBTable table object (full specs are required)
  692. * @param boolean continue to specify if must continue on error (true) or stop (false)
  693. * @param boolean feedback to specify to show status info (true) or not (false)
  694. * @return boolean true on success, false on error
  695. */
  696. function create_table($table, $continue=true, $feedback=true) {
  697. global $CFG, $db;
  698. $status = true;
  699. if (strtolower(get_class($table)) != 'xmldbtable') {
  700. return false;
  701. }
  702. /// Check table doesn't exist
  703. if (table_exists($table)) {
  704. debugging('Table ' . $table->getName() .
  705. ' already exists. Create skipped', DEBUG_DEVELOPER);
  706. return true; //Table exists, nothing to do
  707. }
  708. if(!$sqlarr = $table->getCreateTableSQL($CFG->dbtype, $CFG->prefix, false)) {
  709. return true; //Empty array = nothing to do = no error
  710. }
  711. return execute_sql_arr($sqlarr, $continue, $feedback);
  712. }
  713. /**
  714. * This function will drop the table passed as argument
  715. * and all the associated objects (keys, indexes, constaints, sequences, triggers)
  716. * will be dropped too.
  717. *
  718. * @uses $CFG, $db
  719. * @param XMLDBTable table object (just the name is mandatory)
  720. * @param boolean continue to specify if must continue on error (true) or stop (false)
  721. * @param boolean feedback to specify to show status info (true) or not (false)
  722. * @return boolean true on success, false on error
  723. */
  724. function drop_table($table, $continue=true, $feedback=true) {
  725. global $CFG, $db;
  726. $status = true;
  727. if (strtolower(get_class($table)) != 'xmldbtable') {
  728. return false;
  729. }
  730. /// Check table exists
  731. if (!table_exists($table)) {
  732. debugging('Table ' . $table->getName() .
  733. ' does not exist. Delete skipped', DEBUG_DEVELOPER);
  734. return true; //Table don't exist, nothing to do
  735. }
  736. if(!$sqlarr = $table->getDropTableSQL($CFG->dbtype, $CFG->prefix, false)) {
  737. return true; //Empty array = nothing to do = no error
  738. }
  739. return execute_sql_arr($sqlarr, $continue, $feedback);
  740. }
  741. /**
  742. * This function will create the temporary table passed as argument with all its
  743. * fields/keys/indexes/sequences, everything based in the XMLDB object
  744. *
  745. * TRUNCATE the table immediately after creation. A previous process using
  746. * the same persistent connection may have created the temp table and failed to
  747. * drop it. In that case, the table will exist, and create_temp_table() will
  748. * will succeed.
  749. *
  750. * NOTE: The return value is the tablename - some DBs (MSSQL at least) use special
  751. * names for temp tables.
  752. *
  753. * @uses $CFG, $db
  754. * @param XMLDBTable table object (full specs are required)
  755. * @param boolean continue to specify if must continue on error (true) or stop (false)
  756. * @param boolean feedback to specify to show status info (true) or not (false)
  757. * @return string tablename on success, false on error
  758. */
  759. function create_temp_table($table, $continue=true, $feedback=true) {
  760. global $CFG, $db;
  761. $status = true;
  762. if (strtolower(get_class($table)) != 'xmldbtable') {
  763. return false;
  764. }
  765. $temporary = 'TEMPORARY';
  766. switch (strtolower($CFG->dbfamily)) {
  767. case 'mssql':
  768. // TODO: somehow change the name to have a #
  769. $temporary = '';
  770. break;
  771. case 'oracle':
  772. $temporary = 'GLOBAL TEMPORARY';
  773. break;
  774. }
  775. /// Check table doesn't exist
  776. if (table_exists($table)) {
  777. debugging('Table ' . $table->getName() .
  778. ' already exists. Create skipped', DEBUG_DEVELOPER);
  779. return $table->getName(); //Table exists, nothing to do
  780. }
  781. if(!$sqlarr = $table->getCreateTableSQL($CFG->dbtype, $CFG->prefix, false)) {
  782. return $table->getName(); //Empty array = nothing to do = no error
  783. }
  784. if (!empty($temporary)) {
  785. $sqlarr = preg_replace('/^CREATE/', "CREATE $temporary", $sqlarr);
  786. }
  787. if (execute_sql_arr($sqlarr, $continue, $feedback)) {
  788. return $table->getName();
  789. } else {
  790. return false;
  791. }
  792. }
  793. /**
  794. * This function will rename the table passed as argument
  795. * Before renaming the index, the function will check it exists
  796. *
  797. * @uses $CFG, $db
  798. * @param XMLDBTable table object (just the name is mandatory)
  799. * @param string new name of the index
  800. * @param boolean continue to specify if must continue on error (true) or stop (false)
  801. * @param boolean feedback to specify to show status info (true) or not (false)
  802. * @return boolean true on success, false on error
  803. */
  804. function rename_table($table, $newname, $continue=true, $feedback=true) {
  805. global $CFG, $db;
  806. $status = true;
  807. if (strtolower(get_class($table)) != 'xmldbtable') {
  808. return false;
  809. }
  810. /// Check table exists
  811. if (!table_exists($table)) {
  812. debugging('Table ' . $table->getName() .
  813. ' does not exist. Rename skipped', DEBUG_DEVELOPER);
  814. return true; //Table doesn't exist, nothing to do
  815. }
  816. /// Check new table doesn't exist
  817. $check = new XMLDBTable($newname);
  818. if (table_exists($check)) {
  819. debugging('Table ' . $check->getName() .
  820. ' already exists. Rename skipped', DEBUG_DEVELOPER);
  821. return true; //Table exists, nothing to do
  822. }
  823. /// Check newname isn't empty
  824. if (!$newname) {
  825. debugging('New name for table ' . $table->getName() .
  826. ' is empty! Rename skipped', DEBUG_DEVELOPER);
  827. return true; //Table doesn't exist, nothing to do
  828. }
  829. if(!$sqlarr = $table->getRenameTableSQL($CFG->dbtype, $CFG->prefix, $newname, false)) {
  830. return true; //Empty array = nothing to do = no error
  831. }
  832. return execute_sql_arr($sqlarr, $continue, $feedback);
  833. }
  834. /**
  835. * This function will add the field to the table passed as arguments
  836. *
  837. * @uses $CFG, $db
  838. * @param XMLDBTable table object (just the name is mandatory)
  839. * @param XMLDBField field object (full specs are required)
  840. * @param boolean continue to specify if must continue on error (true) or stop (false)
  841. * @param boolean feedback to specify to show status info (true) or not (false)
  842. * @return boolean true on success, false on error
  843. */
  844. function add_field($table, $field, $continue=true, $feedback=true) {
  845. global $CFG, $db;
  846. $status = true;
  847. if (strtolower(get_class($table)) != 'xmldbtable') {
  848. return false;
  849. }
  850. if (strtolower(get_class($field)) != 'xmldbfield') {
  851. return false;
  852. }
  853. /// Load the needed generator
  854. $classname = 'XMLDB' . $CFG->dbtype;
  855. $generator = new $classname();
  856. $generator->setPrefix($CFG->prefix);
  857. /// Check the field doesn't exist
  858. if (field_exists($table, $field)) {
  859. debugging('Field ' . $table->getName() . '->' . $field->getName() .
  860. ' already exists. Create skipped', DEBUG_DEVELOPER);
  861. return true;
  862. }
  863. /// If NOT NULL and no default given (we ask the generator about the
  864. /// *real* default that will be used) check the table is empty
  865. if ($field->getNotNull() && $generator->getDefaultValue($field) === NULL && count_records($table->getName())) {
  866. debugging('Field ' . $table->getName() . '->' . $field->getName() .
  867. ' cannot be added. Not null fields added to non empty tables require default value. Create skipped', DEBUG_DEVELOPER);
  868. return true;
  869. }
  870. if(!$sqlarr = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
  871. return true; //Empty array = nothing to do = no error
  872. }
  873. return execute_sql_arr($sqlarr, $continue, $feedback);
  874. }
  875. /**
  876. * This function will drop the field from the table passed as arguments
  877. *
  878. * @uses $CFG, $db
  879. * @param XMLDBTable table object (just the name is mandatory)
  880. * @param XMLDBField field object (just the name is mandatory)
  881. * @param boolean continue to specify if must continue on error (true) or stop (false)
  882. * @param boolean feedback to specify to show status info (true) or not (false)
  883. * @return boolean true on success, false on error
  884. */
  885. function drop_field($table, $field, $continue=true, $feedback=true) {
  886. global $CFG, $db;
  887. $status = true;
  888. if (strtolower(get_class($table)) != 'xmldbtable') {
  889. return false;
  890. }
  891. if (strtolower(get_class($field)) != 'xmldbfield') {
  892. return false;
  893. }
  894. /// Check the field exists
  895. if (!field_exists($table, $field)) {
  896. debugging('Field ' . $table->getName() . '->' . $field->getName() .
  897. ' does not exist. Delete skipped', DEBUG_DEVELOPER);
  898. return true;
  899. }
  900. if(!$sqlarr = $table->getDropFieldSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
  901. return true; //Empty array = nothing to do = no error
  902. }
  903. return execute_sql_arr($sqlarr, $continue, $feedback);
  904. }
  905. /**
  906. * This function will change the type of the field in the table passed as arguments
  907. *
  908. * @uses $CFG, $db
  909. * @param XMLDBTable table object (just the name is mandatory)
  910. * @param XMLDBField field object (full specs are required)
  911. * @param boolean continue to specify if must continue on error (true) or stop (false)
  912. * @param boolean feedback to specify to show status info (true) or not (false)
  913. * @return boolean true on success, false on error
  914. */
  915. function change_field_type($table, $field, $continue=true, $feedback=true) {
  916. global $CFG, $db;
  917. $status = true;
  918. if (strtolower(get_class($table)) != 'xmldbtable') {
  919. return false;
  920. }
  921. if (strtolower(get_class($field)) != 'xmldbfield') {
  922. return false;
  923. }
  924. if(!$sqlarr = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
  925. return true; //Empty array = nothing to do = no error
  926. }
  927. return execute_sql_arr($sqlarr, $continue, $feedback);
  928. }
  929. /**
  930. * This function will change the precision of the field in the table passed as arguments
  931. *
  932. * @uses $CFG, $db
  933. * @param XMLDBTable table object (just the name is mandatory)
  934. * @param XMLDBField field object (full specs are required)
  935. * @param boolean continue to specify if must continue on error (true) or stop (false)
  936. * @param boolean feedback to specify to show status info (true) or not (false)
  937. * @return boolean true on success, false on error
  938. */
  939. function change_field_precision($table, $field, $continue=true, $feedback=true) {
  940. /// Just a wrapper over change_field_type. Does exactly the same processing
  941. return change_field_type($table, $field, $continue, $feedback);
  942. }
  943. /**
  944. * This function will change the unsigned/signed of the field in the table passed as arguments
  945. *
  946. * @uses $CFG, $db
  947. * @param XMLDBTable table object (just the name is mandatory)
  948. * @param XMLDBField field object (full specs are required)
  949. * @param boolean continue to specify if must continue on error (true) or stop (false)
  950. * @param boolean feedback to specify to show status info (true) or not (false)
  951. * @return boolean true on success, false on error
  952. */
  953. function change_field_unsigned($table, $field, $continue=true, $feedback=true) {
  954. /// Just a wrapper over change_field_type. Does exactly the same processing
  955. return change_field_type($table, $field, $continue, $feedback);
  956. }
  957. /**
  958. * This function will change the nullability of the field in the table passed as arguments
  959. *
  960. * @uses $CFG, $db
  961. * @param XMLDBTable table object (just the name is mandatory)
  962. * @param XMLDBField field object (full specs are required)
  963. * @param boolean continue to specify if must continue on error (true) or stop (false)
  964. * @param boolean feedback to specify to show status info (true) or not (false)
  965. * @return boolean true on success, false on error
  966. */
  967. function change_field_notnull($table, $field, $continue=true, $feedback=true) {
  968. /// Just a wrapper over change_field_type. Does exactly the same processing
  969. return change_field_type($table, $field, $continue, $feedback);
  970. }
  971. /**
  972. * This function will change the enum status of the field in the table passed as arguments
  973. *
  974. * @uses $CFG, $db
  975. * @param XMLDBTable table object (just the name is mandatory)
  976. * @param XMLDBField field object (full specs are required)
  977. * @param boolean continue to specify if must continue on error (true) or stop (false)
  978. * @param boolean feedback to specify to show status info (true) or not (false)
  979. * @return boolean true on success, false on error
  980. */
  981. function change_field_enum($table, $field, $continue=true, $feedback=true) {
  982. global $CFG, $db;
  983. $status = true;
  984. if (strtolower(get_class($table)) != 'xmldbtable') {
  985. return false;
  986. }
  987. if (strtolower(get_class($field)) != 'xmldbfield') {
  988. return false;
  989. }
  990. /// If enum is defined, we're going to create it, check it doesn't exist.
  991. if ($field->getEnum()) {
  992. if (check_constraint_exists($table, $field)) {
  993. debugging('Enum for ' . $table->getName() . '->' . $field->getName() .
  994. ' already exists. Create skipped', DEBUG_DEVELOPER);
  995. return true; //Enum exists, nothing to do
  996. }
  997. } else { /// Else, we're going to drop it, check it exists
  998. if (!check_constraint_exists($table, $field)) {
  999. debugging('Enum for ' . $table->getName() . '->' . $field->getName() .
  1000. ' does not exist. Delete skipped', DEBUG_DEVELOPER);
  1001. return true; //Enum doesn't exist, nothing to do
  1002. }
  1003. }
  1004. if(!$sqlarr = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
  1005. return true; //Empty array = nothing to do = no error
  1006. }
  1007. return execute_sql_arr($sqlarr, $continue, $feedback);
  1008. }
  1009. /**
  1010. * This function will change the default of the field in the table passed as arguments
  1011. * One null value in the default field means delete the default
  1012. *
  1013. * @uses $CFG, $db
  1014. * @param XMLDBTable table object (just the name is mandatory)
  1015. * @param XMLDBField field object (full specs are required)
  1016. * @param boolean continue to specify if must continue on error (true) or stop (false)
  1017. * @param boolean feedback to specify to show status info (true) or not (false)
  1018. * @return boolean true on success, false on error
  1019. */
  1020. function change_field_default($table, $field, $continue=true, $feedback=true) {
  1021. global $CFG, $db;
  1022. $status = true;
  1023. if (strtolower(get_class($table)) != 'xmldbtable') {
  1024. return false;
  1025. }
  1026. if (strtolower(get_class($field)) != 'xmldbfield') {
  1027. return false;
  1028. }
  1029. if(!$sqlarr = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
  1030. return true; //Empty array = nothing to do = no error
  1031. }
  1032. return execute_sql_arr($sqlarr, $continue, $feedback);
  1033. }
  1034. /**
  1035. * This function will rename the field in the table passed as arguments
  1036. * Before renaming the field, the function will check it exists
  1037. *
  1038. * @uses $CFG, $db
  1039. * @param XMLDBTable table object (just the name is mandatory)
  1040. * @param XMLDBField index object (full specs are required)
  1041. * @param string new name of the field
  1042. * @param boolean continue to specify if must continue on error (true) or stop (false)
  1043. * @param boolean feedback to specify to show status info (true) or not (false)
  1044. * @return boolean true on success, false on error
  1045. */
  1046. function rename_field($table, $field, $newname, $continue=true, $feedback=true) {
  1047. global $CFG, $db;
  1048. $status = true;
  1049. if (strtolower(get_class($table)) != 'xmldbtable') {
  1050. return false;
  1051. }
  1052. if (strtolower(get_class($field)) != 'xmldbfield') {
  1053. return false;
  1054. }
  1055. /// Check we have included full field specs
  1056. if (!$field->getType()) {
  1057. debugging('Field ' . $table->getName() . '->' . $field->getName() .
  1058. ' must contain full specs. Rename skipped', DEBUG_DEVELOPER);
  1059. return false;
  1060. }
  1061. /// Check field isn't id. Renaming over that field is not allowed
  1062. if ($field->getName() == 'id') {
  1063. debugging('Field ' . $table->getName() . '->' . $field->getName() .
  1064. ' cannot be renamed. Rename skipped', DEBUG_DEVELOPER);
  1065. return true; //Field is "id", nothing to do
  1066. }
  1067. /// Check field exists
  1068. if (!field_exists($table, $field)) {
  1069. debugging('Field ' . $table->getName() . '->' . $field->getName() .
  1070. ' does not exist. Rename skipped', DEBUG_DEVELOPER);
  1071. return true; //Field doesn't exist, nothing to do
  1072. }
  1073. /// Check newname isn't empty
  1074. if (!$newname) {
  1075. debugging('New name for field ' . $table->getName() . '->' . $field->getName() .
  1076. ' is empty! Rename skipped', DEBUG_DEVELOPER);
  1077. return true; //Field doesn't exist, nothing to do
  1078. }
  1079. if(!$sqlarr = $table->getRenameFieldSQL($CFG->dbtype, $CFG->prefix, $field, $newname, false)) {
  1080. return true; //Empty array = nothing to do = no error
  1081. }
  1082. return execute_sql_arr($sqlarr, $continue, $feedback);
  1083. }
  1084. /**
  1085. * This function will create the key in the table passed as arguments
  1086. *
  1087. * @uses $CFG, $db
  1088. * @param XMLDBTable table object (just the name is mandatory)
  1089. * @param XMLDBKey index object (full specs are required)
  1090. * @param boolean continue to specify if must continue on error (true) or stop (false)
  1091. * @param boolean feedback to specify to show status info (true) or not (false)
  1092. * @return boolean true on success, false on error
  1093. */
  1094. function add_key($table, $key, $continue=true, $feedback=true) {
  1095. global $CFG, $db;
  1096. $status = true;
  1097. if (strtolower(get_class($table)) != 'xmldbtable') {
  1098. return false;
  1099. }
  1100. if (strtolower(get_class($key)) != 'xmldbkey') {
  1101. return false;
  1102. }
  1103. if ($key->getType() == XMLDB_KEY_PRIMARY) { // Prevent PRIMARY to be added (only in create table, being serious :-P)
  1104. debugging('Primary Keys can be added at table create time only', DEBUG_DEVELOPER);
  1105. return true;
  1106. }
  1107. if(!$sqlarr = $table->getAddKeySQL($CFG->dbtype, $CFG->prefix, $key, false)) {
  1108. return true; //Empty array = nothing to do = no error
  1109. }
  1110. return execute_sql_arr($sqlarr, $continue, $feedback);
  1111. }
  1112. /**
  1113. * This function will drop the key in the table passed as arguments
  1114. *
  1115. * @uses $CFG, $db
  1116. * @param XMLDBTable table object (just the name is mandatory)
  1117. * @param XMLDBKey key object (full specs are required)
  1118. * @param boolean continue to specify if must continue on error (true) or stop (false)
  1119. * @param boolean feedback to specify to show status info (true) or not (false)
  1120. * @return boolean true on success, false on error
  1121. */
  1122. function drop_key($table, $key, $continue=true, $feedback=true) {
  1123. global $CFG, $db;
  1124. $status = true;
  1125. if (strtolower(get_class($table)) != 'xmldbtable') {
  1126. return false;
  1127. }
  1128. if (strtolower(get_class($key)) != 'xmldbkey') {
  1129. return false;
  1130. }
  1131. if ($key->getType() == XMLDB_KEY_PRIMARY) { // Prevent PRIMARY to be dropped (only in drop table, being serious :-P)
  1132. debugging('Primary Keys can be deleted at table drop time only', DEBUG_DEVELOPER);
  1133. return true;
  1134. }
  1135. if(!$sqlarr = $table->getDropKeySQL($CFG->dbtype, $CFG->prefix, $key, false)) {
  1136. return true; //Empty array = nothing to do = no error
  1137. }
  1138. return execute_sql_arr($sqlarr, $continue, $feedback);
  1139. }
  1140. /**
  1141. * This function will rename the key in the table passed as arguments
  1142. * Experimental. Shouldn't be used at all in normal installation/upgrade!
  1143. *
  1144. * @uses $CFG, $db
  1145. * @param XMLDBTable table object (just the name is mandatory)
  1146. * @param XMLDBKey key object (full specs are required)
  1147. * @param string new name of the key
  1148. * @param boolean continue to specify if must continue on error (true) or stop (false)
  1149. * @param boolean feedback to specify to show status info (true) or not (false)
  1150. * @return boolean true on success, false on error
  1151. */
  1152. function rename_key($table, $key, $newname, $continue=true, $feedback=true) {
  1153. global $CFG, $db;
  1154. debugging('rename_key() is one experimental feature. You must not use it in production!', DEBUG_DEVELOPER);
  1155. $status = true;
  1156. if (strtolower(get_class($table)) != 'xmldbtable') {
  1157. return false;
  1158. }
  1159. if (strtolower(get_class($key)) != 'xmldbkey') {
  1160. return false;
  1161. }
  1162. /// Check newname isn't empty
  1163. if (!$newname) {
  1164. debugging('New name for key ' . $table->getName() . '->' . $key->getName() .
  1165. ' is empty! Rename skipped', DEBUG_DEVELOPER);
  1166. return true; //Key doesn't exist, nothing to do
  1167. }
  1168. if(!$sqlarr = $table->getRenameKeySQL($CFG->dbtype, $CFG->prefix, $key, $newname, false)) {
  1169. debugging('Some DBs do not support key renaming (MySQL, PostgreSQL, MsSQL). Rename skipped', DEBUG_DEVELOPER);
  1170. return true; //Empty array = nothing to do = no error
  1171. }
  1172. return execute_sql_arr($sqlarr, $continue, $feedback);
  1173. }

Large files files are truncated, but you can click here to view the full file