3 ///////////////////////////////////////////////////////////////////////////
5 // NOTICE OF COPYRIGHT //
7 // Moodle - Modular Object-Oriented Dynamic Learning Environment //
8 // http://moodle.com //
10 // Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
11 // (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
13 // This program is free software; you can redistribute it and/or modify //
14 // it under the terms of the GNU General Public License as published by //
15 // the Free Software Foundation; either version 2 of the License, or //
16 // (at your option) any later version. //
18 // This program is distributed in the hope that it will be useful, //
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
21 // GNU General Public License for more details: //
23 // http://www.gnu.org/copyleft/gpl.html //
25 ///////////////////////////////////////////////////////////////////////////
27 // This library includes all the required functions used to handle the DB
28 // structure (DDL) independently of the underlying RDBMS in use. All the functions
29 // rely on the XMLDBDriver classes to be able to generate the correct SQL
30 // syntax needed by each DB.
32 // To define any structure to be created we'll use the schema defined
33 // by the XMLDB classes, for tables, fields, indexes, keys and other
34 // statements instead of direct handling of SQL sentences.
36 // This library should be used, exclusively, by the installation and
37 // upgrade process of Moodle.
39 // For further documentation, visit http://docs.moodle.org/en/DDL_functions
41 /// Add required XMLDB constants
42 require_once($CFG->libdir
. '/xmldb/classes/XMLDBConstants.php');
44 /// Add main XMLDB Generator
45 require_once($CFG->libdir
. '/xmldb/classes/generators/XMLDBGenerator.class.php');
47 /// Add required XMLDB DB classes
48 require_once($CFG->libdir
. '/xmldb/classes/XMLDBObject.class.php');
49 require_once($CFG->libdir
. '/xmldb/classes/XMLDBFile.class.php');
50 require_once($CFG->libdir
. '/xmldb/classes/XMLDBStructure.class.php');
51 require_once($CFG->libdir
. '/xmldb/classes/XMLDBTable.class.php');
52 require_once($CFG->libdir
. '/xmldb/classes/XMLDBField.class.php');
53 require_once($CFG->libdir
. '/xmldb/classes/XMLDBKey.class.php');
54 require_once($CFG->libdir
. '/xmldb/classes/XMLDBIndex.class.php');
55 require_once($CFG->libdir
. '/xmldb/classes/XMLDBStatement.class.php');
57 /// Based on $CFG->dbtype, add the proper generator class
58 if (!file_exists($CFG->libdir
. '/xmldb/classes/generators/' . $CFG->dbtype
. '/' . $CFG->dbtype
. '.class.php')) {
59 error ('DB Type: ' . $CFG->dbtype
. ' not supported by XMLDDB');
61 require_once($CFG->libdir
. '/xmldb/classes/generators/' . $CFG->dbtype
. '/' . $CFG->dbtype
. '.class.php');
64 /// Add other libraries
65 require_once($CFG->libdir
. '/xmlize.php');
67 * Add a new field to a table, or modify an existing one (if oldfield is defined).
68 * Warning: Please be careful on primary keys, as this function will eat auto_increments
72 * @param string $table the name of the table to modify. (Without the prefix.)
73 * @param string $oldfield If changing an existing column, the name of that column.
74 * @param string $field The name of the column at the end of the operation.
75 * @param string $type The type of the column at the end of the operation. TEXT, VARCHAR, CHAR, INTEGER, REAL, or TINYINT
76 * @param string $size The size of that column type. As in VARCHAR($size), or INTEGER($size).
77 * @param string $signed For numeric column types, whether that column is 'signed' or 'unsigned'.
78 * @param string $default The new default value for the column.
79 * @param string $null 'not null', or '' to allow nulls.
80 * @param string $after Which column to insert this one after. Not supported on Postgres.
82 * @return boolean Wheter the operation succeeded.
84 function table_column($table, $oldfield, $field, $type='integer', $size='10',
85 $signed='unsigned', $default='0', $null='not null', $after='') {
86 global $CFG, $db, $empty_rs_cache;
88 if (!empty($empty_rs_cache[$table])) { // Clear the recordset cache because it's out of date
89 unset($empty_rs_cache[$table]);
92 switch (strtolower($CFG->dbtype
)) {
97 switch (strtolower($type)) {
103 $type = 'INTEGER('. $size .')';
106 $type = 'VARCHAR('. $size .')';
110 $type = 'CHAR('. $size .')';
115 if (!empty($oldfield)) {
116 $operation = 'CHANGE '. $oldfield .' '. $field;
118 $operation = 'ADD '. $field;
121 $default = 'DEFAULT \''. $default .'\'';
123 if (!empty($after)) {
124 $after = 'AFTER `'. $after .'`';
127 return execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' '. $operation .' '. $type .' '. $signed .' '. $default .' '. $null .' '. $after);
129 case 'postgres7': // From Petri Asikainen
131 $dbinfo = $db->ServerInfo();
132 $dbver = substr($dbinfo['version'],0,3);
134 //to prevent conflicts with reserved words
135 $realfield = '"'. $field .'"';
136 $field = '"'. $field .'_alter_column_tmp"';
137 $oldfield = '"'. $oldfield .'"';
139 switch (strtolower($type)) {
153 $type = 'VARCHAR('. $size .')';
156 $type = 'CHAR('. $size .')';
161 $default = '\''. $default .'\'';
163 //After is not implemented in postgesql
164 //if (!empty($after)) {
165 // $after = "AFTER '$after'";
169 execute_sql('BEGIN');
171 //Always use temporary column
172 execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' ADD COLUMN '. $field .' '. $type);
174 execute_sql('UPDATE '. $CFG->prefix
. $table .' SET '. $field .'='. $default);
177 if ($dbver >= '7.3') {
178 // modifying 'not null' is posible before 7.3
179 //update default values to table
180 if (strtoupper($null) == 'NOT NULL') {
181 execute_sql('UPDATE '. $CFG->prefix
. $table .' SET '. $field .'='. $default .' WHERE '. $field .' IS NULL');
182 execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' ALTER COLUMN '. $field .' SET '. $null);
184 execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' ALTER COLUMN '. $field .' DROP NOT NULL');
188 execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' ALTER COLUMN '. $field .' SET DEFAULT '. $default);
190 if ( $oldfield != '""' ) {
192 // We are changing the type of a column. This may require doing some casts...
194 $oldtype = column_type($table, $oldfield);
195 $newtype = column_type($table, $field);
197 // Do we need a cast?
198 if($newtype == 'N' && $oldtype == 'C') {
199 $casting = 'CAST(CAST('.$oldfield.' AS TEXT) AS REAL)';
201 else if($newtype == 'I' && $oldtype == 'C') {
202 $casting = 'CAST(CAST('.$oldfield.' AS TEXT) AS INTEGER)';
205 $casting = $oldfield;
208 // Run the update query, casting as necessary
209 execute_sql('UPDATE '. $CFG->prefix
. $table .' SET '. $field .' = '. $casting);
210 execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' DROP COLUMN '. $oldfield);
213 execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' RENAME COLUMN '. $field .' TO '. $realfield);
215 return execute_sql('COMMIT');
218 switch (strtolower($type)) {
227 $default = 'DEFAULT \''. $default .'\'';
229 if (!empty($after)) {
230 $after = 'AFTER '. $after;
233 if (!empty($oldfield)) {
234 execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' RENAME COLUMN '. $oldfield .' '. $field);
236 execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' ADD COLUMN '. $field .' '. $type);
239 execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' ALTER COLUMN '. $field .' SET '. $null);
240 return execute_sql('ALTER TABLE '. $CFG->prefix
. $table .' ALTER COLUMN '. $field .' SET '. $default);
245 * Given one XMLDBTable, check if it exists in DB (true/false)
247 * @param XMLDBTable table to be searched for
248 * @return boolean true/false
250 function table_exists($table) {
256 /// Do this function silenty (to avoid output in install/upgrade process)
257 $olddbdebug = $db->debug
;
260 /// Load the needed generator
261 $classname = 'XMLDB' . $CFG->dbtype
;
262 $generator = new $classname();
263 $generator->setPrefix($CFG->prefix
);
264 /// Calculate the name of the table
265 $tablename = $generator->getTableName($table, false);
267 /// Search such tablename in DB
268 $metatables = $db->MetaTables();
269 $metatables = array_flip($metatables);
270 $metatables = array_change_key_case($metatables, CASE_LOWER
);
271 if (!array_key_exists($tablename, $metatables)) {
275 /// Re-set original debug
276 $db->debug
= $olddbdebug;
282 * Given one XMLDBField, check if it exists in DB (true/false)
285 * @param XMLDBTable the table
286 * @param XMLDBField the field to be searched for
287 * @return boolean true/false
289 function field_exists($table, $field) {
295 /// Do this function silenty (to avoid output in install/upgrade process)
296 $olddbdebug = $db->debug
;
299 /// Check the table exists
300 if (!table_exists($table)) {
301 $db->debug
= $olddbdebug; //Re-set original $db->debug
305 /// Load the needed generator
306 $classname = 'XMLDB' . $CFG->dbtype
;
307 $generator = new $classname();
308 $generator->setPrefix($CFG->prefix
);
309 /// Calculate the name of the table
310 $tablename = $generator->getTableName($table, false);
312 /// Get list of fields in table
314 if ($fields = $db->MetaColumns($tablename)) {
315 $fields = array_change_key_case($fields, CASE_LOWER
);
318 if (!array_key_exists($field->getName(), $fields)) {
322 /// Re-set original debug
323 $db->debug
= $olddbdebug;
329 * Given one XMLDBIndex, check if it exists in DB (true/false)
332 * @param XMLDBTable the table
333 * @param XMLDBIndex the index to be searched for
334 * @return boolean true/false
336 function index_exists($table, $index) {
342 /// Do this function silenty (to avoid output in install/upgrade process)
343 $olddbdebug = $db->debug
;
346 /// Wrap over find_index_name to see if the index exists
347 if (!find_index_name($table, $index)) {
351 /// Re-set original debug
352 $db->debug
= $olddbdebug;
358 * Given one XMLDBField, check if it has a check constraint in DB
361 * @param XMLDBTable the table
362 * @param XMLDBField the field to be searched for any existing constraint
363 * @return boolean true/false
365 function check_constraint_exists($table, $field) {
371 /// Do this function silenty (to avoid output in install/upgrade process)
372 $olddbdebug = $db->debug
;
375 /// Wrap over find_check_constraint_name to see if the index exists
376 if (!find_check_constraint_name($table, $field)) {
380 /// Re-set original debug
381 $db->debug
= $olddbdebug;
387 * This function IS NOT IMPLEMENTED. ONCE WE'LL BE USING RELATIONAL
388 * INTEGRITY IT WILL BECOME MORE USEFUL. FOR NOW, JUST CALCULATE "OFFICIAL"
389 * KEY NAMES WITHOUT ACCESSING TO DB AT ALL.
390 * Given one XMLDBKey, the function returns the name of the key in DB (if exists)
391 * of false if it doesn't exist
394 * @param XMLDBTable the table to be searched
395 * @param XMLDBKey the key to be searched
396 * @return string key name of false
398 function find_key_name($table, $xmldb_key) {
402 /// Extract key columns
403 $keycolumns = $xmldb_key->getFields();
405 /// Get list of keys in table
406 /// first primaries (we aren't going to use this now, because the MetaPrimaryKeys is awful)
407 ///TODO: To implement when we advance in relational integrity
408 /// then uniques (note that Moodle, for now, shouldn't have any UNIQUE KEY for now, but unique indexes)
409 ///TODO: To implement when we advance in relational integrity (note that AdoDB hasn't any MetaXXX for this.
410 /// then foreign (note that Moodle, for now, shouldn't have any FOREIGN KEY for now, but indexes)
411 ///TODO: To implement when we advance in relational integrity (note that AdoDB has one MetaForeignKeys()
412 ///but it's far from perfect.
413 /// TODO: To create the proper functions inside each generator to retrieve all the needed KEY info (name
414 /// columns, reftable and refcolumns
416 /// So all we do is to return the official name of the requested key without any confirmation!)
417 $classname = 'XMLDB' . $CFG->dbtype
;
418 $generator = new $classname();
419 $generator->setPrefix($CFG->prefix
);
420 /// One exception, harcoded primary constraint names
421 if ($generator->primary_key_name
&& $xmldb_key->getType() == XMLDB_KEY_PRIMARY
) {
422 return $generator->primary_key_name
;
424 /// Calculate the name suffix
425 switch ($xmldb_key->getType()) {
426 case XMLDB_KEY_PRIMARY
:
429 case XMLDB_KEY_UNIQUE
:
432 case XMLDB_KEY_FOREIGN_UNIQUE
:
433 case XMLDB_KEY_FOREIGN
:
437 /// And simply, return the oficial name
438 return $generator->getNameForObject($table->getName(), implode(', ', $xmldb_key->getFields()), $suffix);
443 * Given one XMLDBIndex, the function returns the name of the index in DB (if exists)
444 * of false if it doesn't exist
447 * @param XMLDBTable the table to be searched
448 * @param XMLDBIndex the index to be searched
449 * @return string index name of false
451 function find_index_name($table, $index) {
455 /// Do this function silenty (to avoid output in install/upgrade process)
456 $olddbdebug = $db->debug
;
459 /// Extract index columns
460 $indcolumns = $index->getFields();
462 /// Check the table exists
463 if (!table_exists($table)) {
464 $db->debug
= $olddbdebug; //Re-set original $db->debug
468 /// Load the needed generator
469 $classname = 'XMLDB' . $CFG->dbtype
;
470 $generator = new $classname();
471 $generator->setPrefix($CFG->prefix
);
472 /// Calculate the name of the table
473 $tablename = $generator->getTableName($table, false);
475 /// Get list of indexes in table
477 if ($indexes = $db->MetaIndexes($tablename)) {
478 $indexes = array_change_key_case($indexes, CASE_LOWER
);
481 /// Iterate over them looking for columns coincidence
483 foreach ($indexes as $indexname => $index) {
484 $columns = $index['columns'];
485 /// Lower case column names
486 $columns = array_flip($columns);
487 $columns = array_change_key_case($columns, CASE_LOWER
);
488 $columns = array_flip($columns);
489 /// Check if index matchs queried index
490 $diferences = array_merge(array_diff($columns, $indcolumns), array_diff($indcolumns, $columns));
491 /// If no diferences, we have find the index
492 if (empty($diferences)) {
493 $db->debug
= $olddbdebug; //Re-set original $db->debug
498 /// Arriving here, index not found
499 $db->debug
= $olddbdebug; //Re-set original $db->debug
504 * Given one XMLDBField, the function returns the name of the check constraint in DB (if exists)
505 * of false if it doesn't exist. Note that XMLDB limits the number of check constrainst per field
506 * to 1 "enum-like" constraint. So, if more than one is returned, only the first one will be
507 * retrieved by this funcion.
510 * @param XMLDBTable the table to be searched
511 * @param XMLDBField the field to be searched
512 * @return string check consrtaint name or false
514 function find_check_constraint_name($table, $field) {
518 /// Do this function silenty (to avoid output in install/upgrade process)
519 $olddbdebug = $db->debug
;
522 /// Check the table exists
523 if (!table_exists($table)) {
524 $db->debug
= $olddbdebug; //Re-set original $db->debug
528 /// Check the field exists
529 if (!field_exists($table, $field)) {
530 $db->debug
= $olddbdebug; //Re-set original $db->debug
534 /// Load the needed generator
535 $classname = 'XMLDB' . $CFG->dbtype
;
536 $generator = new $classname();
537 $generator->setPrefix($CFG->prefix
);
538 /// Calculate the name of the table
539 $tablename = $generator->getTableName($table, false);
541 /// Get list of check_constraints in table/field
543 if ($objchecks = $generator->getCheckConstraintsFromDB($table, $field)) {
544 /// Get only the 1st element. Shouldn't be more than 1 under XMLDB
545 $objcheck = array_shift($objchecks);
547 $checks = strtolower($objcheck->name
);
551 /// Arriving here, check not found
552 $db->debug
= $olddbdebug; //Re-set original $db->debug
557 * Given one XMLDBTable, the function returns the name of its sequence in DB (if exists)
558 * of false if it doesn't exist
560 * @param XMLDBTable the table to be searched
561 * @return string sequence name of false
563 function find_sequence_name($table) {
567 $sequencename = false;
569 /// Do this function silenty (to avoid output in install/upgrade process)
570 $olddbdebug = $db->debug
;
573 if (strtolower(get_class($table)) != 'xmldbtable') {
574 $db->debug
= $olddbdebug; //Re-set original $db->debug
578 /// Check table exists
579 if (!table_exists($table)) {
580 debugging('Table ' . $table->getName() .
581 ' does not exist. Sequence not found', DEBUG_DEVELOPER
);
582 $db->debug
= $olddbdebug; //Re-set original $db->debug
583 return false; //Table doesn't exist, nothing to do
586 $sequencename = $table->getSequenceFromDB($CFG->dbtype
, $CFG->prefix
);
588 $db->debug
= $olddbdebug; //Re-set original $db->debug
589 return $sequencename;
593 * This function will load one entire XMLDB file, generating all the needed
594 * SQL statements, specific for each RDBMS ($CFG->dbtype) and, finally, it
595 * will execute all those statements against the DB.
598 * @param $file full path to the XML file to be used
599 * @return boolean (true on success, false on error)
601 function install_from_xmldb_file($file) {
608 $xmldb_file = new XMLDBFile($file);
610 if (!$xmldb_file->fileExists()) {
614 $loaded = $xmldb_file->loadXMLStructure();
615 if (!$loaded ||
!$xmldb_file->isLoaded()) {
616 /// Show info about the error if we can find it
617 if ($structure =& $xmldb_file->getStructure()) {
618 if ($errors = $structure->getAllErrors()) {
619 notify('Errors found in XMLDB file: '. implode (', ', $errors));
625 $structure = $xmldb_file->getStructure();
627 if (!$sqlarr = $structure->getCreateStructureSQL($CFG->dbtype
, $CFG->prefix
, false)) {
628 return true; //Empty array = nothing to do = no error
631 return execute_sql_arr($sqlarr);
635 * This function will create the table passed as argument with all its
636 * fields/keys/indexes/sequences, everything based in the XMLDB object
639 * @param XMLDBTable table object (full specs are required)
640 * @param boolean continue to specify if must continue on error (true) or stop (false)
641 * @param boolean feedback to specify to show status info (true) or not (false)
642 * @return boolean true on success, false on error
644 function create_table($table, $continue=true, $feedback=true) {
650 if (strtolower(get_class($table)) != 'xmldbtable') {
654 /// Check table doesn't exist
655 if (table_exists($table)) {
656 debugging('Table ' . $table->getName() .
657 ' already exists. Create skipped', DEBUG_DEVELOPER
);
658 return true; //Table exists, nothing to do
661 if(!$sqlarr = $table->getCreateTableSQL($CFG->dbtype
, $CFG->prefix
, false)) {
662 return true; //Empty array = nothing to do = no error
665 return execute_sql_arr($sqlarr, $continue, $feedback);
669 * This function will drop the table passed as argument
670 * and all the associated objects (keys, indexes, constaints, sequences, triggers)
671 * will be dropped too.
674 * @param XMLDBTable table object (just the name is mandatory)
675 * @param boolean continue to specify if must continue on error (true) or stop (false)
676 * @param boolean feedback to specify to show status info (true) or not (false)
677 * @return boolean true on success, false on error
679 function drop_table($table, $continue=true, $feedback=true) {
685 if (strtolower(get_class($table)) != 'xmldbtable') {
689 /// Check table exists
690 if (!table_exists($table)) {
691 debugging('Table ' . $table->getName() .
692 ' does not exist. Delete skipped', DEBUG_DEVELOPER
);
693 return true; //Table don't exist, nothing to do
696 if(!$sqlarr = $table->getDropTableSQL($CFG->dbtype
, $CFG->prefix
, false)) {
697 return true; //Empty array = nothing to do = no error
700 return execute_sql_arr($sqlarr, $continue, $feedback);
704 * This function will create the temporary table passed as argument with all its
705 * fields/keys/indexes/sequences, everything based in the XMLDB object
707 * TRUNCATE the table immediately after creation. A previous process using
708 * the same persistent connection may have created the temp table and failed to
709 * drop it. In that case, the table will exist, and create_temp_table() will
712 * NOTE: The return value is the tablename - some DBs (MSSQL at least) use special
713 * names for temp tables.
716 * @param XMLDBTable table object (full specs are required)
717 * @param boolean continue to specify if must continue on error (true) or stop (false)
718 * @param boolean feedback to specify to show status info (true) or not (false)
719 * @return string tablename on success, false on error
721 function create_temp_table($table, $continue=true, $feedback=true) {
727 if (strtolower(get_class($table)) != 'xmldbtable') {
732 $temporary = 'TEMPORARY';
733 switch (strtolower($CFG->dbfamily
)) {
735 // TODO: somehow change the name to have a #
739 $temporary = 'GLOBAL TEMPORARY';
743 /// Check table doesn't exist
744 if (table_exists($table)) {
745 debugging('Table ' . $table->getName() .
746 ' already exists. Create skipped', DEBUG_DEVELOPER
);
747 return $table->getName(); //Table exists, nothing to do
750 if(!$sqlarr = $table->getCreateTableSQL($CFG->dbtype
, $CFG->prefix
, false)) {
751 return $table->getName(); //Empty array = nothing to do = no error
754 if (!empty($temporary)) {
755 $sqlarr = preg_replace('/^CREATE/', "CREATE $temporary", $sqlarr);
758 if (execute_sql_arr($sqlarr, $continue, $feedback)) {
759 return $table->getName();
766 * This function will rename the table passed as argument
767 * Before renaming the index, the function will check it exists
770 * @param XMLDBTable table object (just the name is mandatory)
771 * @param string new name of the index
772 * @param boolean continue to specify if must continue on error (true) or stop (false)
773 * @param boolean feedback to specify to show status info (true) or not (false)
774 * @return boolean true on success, false on error
776 function rename_table($table, $newname, $continue=true, $feedback=true) {
782 if (strtolower(get_class($table)) != 'xmldbtable') {
786 /// Check table exists
787 if (!table_exists($table)) {
788 debugging('Table ' . $table->getName() .
789 ' does not exist. Rename skipped', DEBUG_DEVELOPER
);
790 return true; //Table doesn't exist, nothing to do
793 /// Check new table doesn't exist
794 $check = new XMLDBTable($newname);
795 if (table_exists($check)) {
796 debugging('Table ' . $check->getName() .
797 ' already exists. Rename skipped', DEBUG_DEVELOPER
);
798 return true; //Table exists, nothing to do
801 /// Check newname isn't empty
803 debugging('New name for table ' . $table->getName() .
804 ' is empty! Rename skipped', DEBUG_DEVELOPER
);
805 return true; //Table doesn't exist, nothing to do
808 if(!$sqlarr = $table->getRenameTableSQL($CFG->dbtype
, $CFG->prefix
, $newname, false)) {
809 return true; //Empty array = nothing to do = no error
812 return execute_sql_arr($sqlarr, $continue, $feedback);
816 * This function will add the field to the table passed as arguments
819 * @param XMLDBTable table object (just the name is mandatory)
820 * @param XMLDBField field object (full specs are required)
821 * @param boolean continue to specify if must continue on error (true) or stop (false)
822 * @param boolean feedback to specify to show status info (true) or not (false)
823 * @return boolean true on success, false on error
825 function add_field($table, $field, $continue=true, $feedback=true) {
831 if (strtolower(get_class($table)) != 'xmldbtable') {
834 if (strtolower(get_class($field)) != 'xmldbfield') {
838 /// Load the needed generator
839 $classname = 'XMLDB' . $CFG->dbtype
;
840 $generator = new $classname();
841 $generator->setPrefix($CFG->prefix
);
843 /// Check the field doesn't exist
844 if (field_exists($table, $field)) {
845 debugging('Field ' . $table->getName() . '->' . $field->getName() .
846 ' already exists. Create skipped', DEBUG_DEVELOPER
);
850 /// If NOT NULL and no default given (we ask the generator about the
851 /// *real* default that will be used) check the table is empty
852 if ($field->getNotNull() && $generator->getDefaultValue($field) === NULL && count_records($table->getName())) {
853 debugging('Field ' . $table->getName() . '->' . $field->getName() .
854 ' cannot be added. Not null fields added to non empty tables require default value. Create skipped', DEBUG_DEVELOPER
);
858 if(!$sqlarr = $table->getAddFieldSQL($CFG->dbtype
, $CFG->prefix
, $field, false)) {
859 return true; //Empty array = nothing to do = no error
862 return execute_sql_arr($sqlarr, $continue, $feedback);
866 * This function will drop the field from the table passed as arguments
869 * @param XMLDBTable table object (just the name is mandatory)
870 * @param XMLDBField field object (just the name is mandatory)
871 * @param boolean continue to specify if must continue on error (true) or stop (false)
872 * @param boolean feedback to specify to show status info (true) or not (false)
873 * @return boolean true on success, false on error
875 function drop_field($table, $field, $continue=true, $feedback=true) {
881 if (strtolower(get_class($table)) != 'xmldbtable') {
884 if (strtolower(get_class($field)) != 'xmldbfield') {
888 /// Check the field exists
889 if (!field_exists($table, $field)) {
890 debugging('Field ' . $table->getName() . '->' . $field->getName() .
891 ' does not exist. Delete skipped', DEBUG_DEVELOPER
);
895 if(!$sqlarr = $table->getDropFieldSQL($CFG->dbtype
, $CFG->prefix
, $field, false)) {
896 return true; //Empty array = nothing to do = no error
899 return execute_sql_arr($sqlarr, $continue, $feedback);
903 * This function will change the type of the field in the table passed as arguments
906 * @param XMLDBTable table object (just the name is mandatory)
907 * @param XMLDBField field object (full specs are required)
908 * @param boolean continue to specify if must continue on error (true) or stop (false)
909 * @param boolean feedback to specify to show status info (true) or not (false)
910 * @return boolean true on success, false on error
912 function change_field_type($table, $field, $continue=true, $feedback=true) {
918 if (strtolower(get_class($table)) != 'xmldbtable') {
921 if (strtolower(get_class($field)) != 'xmldbfield') {
925 if(!$sqlarr = $table->getAlterFieldSQL($CFG->dbtype
, $CFG->prefix
, $field, false)) {
926 return true; //Empty array = nothing to do = no error
929 return execute_sql_arr($sqlarr, $continue, $feedback);
933 * This function will change the precision of the field in the table passed as arguments
936 * @param XMLDBTable table object (just the name is mandatory)
937 * @param XMLDBField field object (full specs are required)
938 * @param boolean continue to specify if must continue on error (true) or stop (false)
939 * @param boolean feedback to specify to show status info (true) or not (false)
940 * @return boolean true on success, false on error
942 function change_field_precision($table, $field, $continue=true, $feedback=true) {
944 /// Just a wrapper over change_field_type. Does exactly the same processing
945 return change_field_type($table, $field, $continue, $feedback);
949 * This function will change the unsigned/signed of the field in the table passed as arguments
952 * @param XMLDBTable table object (just the name is mandatory)
953 * @param XMLDBField field object (full specs are required)
954 * @param boolean continue to specify if must continue on error (true) or stop (false)
955 * @param boolean feedback to specify to show status info (true) or not (false)
956 * @return boolean true on success, false on error
958 function change_field_unsigned($table, $field, $continue=true, $feedback=true) {
960 /// Just a wrapper over change_field_type. Does exactly the same processing
961 return change_field_type($table, $field, $continue, $feedback);
965 * This function will change the nullability of the field in the table passed as arguments
968 * @param XMLDBTable table object (just the name is mandatory)
969 * @param XMLDBField field object (full specs are required)
970 * @param boolean continue to specify if must continue on error (true) or stop (false)
971 * @param boolean feedback to specify to show status info (true) or not (false)
972 * @return boolean true on success, false on error
974 function change_field_notnull($table, $field, $continue=true, $feedback=true) {
976 /// Just a wrapper over change_field_type. Does exactly the same processing
977 return change_field_type($table, $field, $continue, $feedback);
981 * This function will change the enum status of the field in the table passed as arguments
984 * @param XMLDBTable table object (just the name is mandatory)
985 * @param XMLDBField field object (full specs are required)
986 * @param boolean continue to specify if must continue on error (true) or stop (false)
987 * @param boolean feedback to specify to show status info (true) or not (false)
988 * @return boolean true on success, false on error
990 function change_field_enum($table, $field, $continue=true, $feedback=true) {
996 if (strtolower(get_class($table)) != 'xmldbtable') {
999 if (strtolower(get_class($field)) != 'xmldbfield') {
1003 /// If enum is defined, we're going to create it, check it doesn't exist.
1004 if ($field->getEnum()) {
1005 if (check_constraint_exists($table, $field)) {
1006 debugging('Enum for ' . $table->getName() . '->' . $field->getName() .
1007 ' already exists. Create skipped', DEBUG_DEVELOPER
);
1008 return true; //Enum exists, nothing to do
1010 } else { /// Else, we're going to drop it, check it exists
1011 if (!check_constraint_exists($table, $field)) {
1012 debugging('Enum for ' . $table->getName() . '->' . $field->getName() .
1013 ' does not exist. Delete skipped', DEBUG_DEVELOPER
);
1014 return true; //Enum doesn't exist, nothing to do
1018 if(!$sqlarr = $table->getModifyEnumSQL($CFG->dbtype
, $CFG->prefix
, $field, false)) {
1019 return true; //Empty array = nothing to do = no error
1022 return execute_sql_arr($sqlarr, $continue, $feedback);
1025 * This function will change the default of the field in the table passed as arguments
1026 * One null value in the default field means delete the default
1029 * @param XMLDBTable table object (just the name is mandatory)
1030 * @param XMLDBField field object (full specs are required)
1031 * @param boolean continue to specify if must continue on error (true) or stop (false)
1032 * @param boolean feedback to specify to show status info (true) or not (false)
1033 * @return boolean true on success, false on error
1035 function change_field_default($table, $field, $continue=true, $feedback=true) {
1041 if (strtolower(get_class($table)) != 'xmldbtable') {
1044 if (strtolower(get_class($field)) != 'xmldbfield') {
1048 if(!$sqlarr = $table->getModifyDefaultSQL($CFG->dbtype
, $CFG->prefix
, $field, false)) {
1049 return true; //Empty array = nothing to do = no error
1052 return execute_sql_arr($sqlarr, $continue, $feedback);
1056 * This function will rename the field in the table passed as arguments
1057 * Before renaming the field, the function will check it exists
1060 * @param XMLDBTable table object (just the name is mandatory)
1061 * @param XMLDBField index object (full specs are required)
1062 * @param string new name of the field
1063 * @param boolean continue to specify if must continue on error (true) or stop (false)
1064 * @param boolean feedback to specify to show status info (true) or not (false)
1065 * @return boolean true on success, false on error
1067 function rename_field($table, $field, $newname, $continue=true, $feedback=true) {
1073 if (strtolower(get_class($table)) != 'xmldbtable') {
1076 if (strtolower(get_class($field)) != 'xmldbfield') {
1080 /// Check we have included full field specs
1081 if (!$field->getType()) {
1082 debugging('Field ' . $table->getName() . '->' . $field->getName() .
1083 ' must contain full specs. Rename skipped', DEBUG_DEVELOPER
);
1087 /// Check field isn't id. Renaming over that field is not allowed
1088 if ($field->getName() == 'id') {
1089 debugging('Field ' . $table->getName() . '->' . $field->getName() .
1090 ' cannot be renamed. Rename skipped', DEBUG_DEVELOPER
);
1091 return true; //Field is "id", nothing to do
1094 /// Check field exists
1095 if (!field_exists($table, $field)) {
1096 debugging('Field ' . $table->getName() . '->' . $field->getName() .
1097 ' does not exist. Rename skipped', DEBUG_DEVELOPER
);
1098 return true; //Field doesn't exist, nothing to do
1101 /// Check newname isn't empty
1103 debugging('New name for field ' . $table->getName() . '->' . $field->getName() .
1104 ' is empty! Rename skipped', DEBUG_DEVELOPER
);
1105 return true; //Field doesn't exist, nothing to do
1108 if(!$sqlarr = $table->getRenameFieldSQL($CFG->dbtype
, $CFG->prefix
, $field, $newname, false)) {
1109 return true; //Empty array = nothing to do = no error
1112 return execute_sql_arr($sqlarr, $continue, $feedback);
1116 * This function will create the key in the table passed as arguments
1119 * @param XMLDBTable table object (just the name is mandatory)
1120 * @param XMLDBKey index object (full specs are required)
1121 * @param boolean continue to specify if must continue on error (true) or stop (false)
1122 * @param boolean feedback to specify to show status info (true) or not (false)
1123 * @return boolean true on success, false on error
1125 function add_key($table, $key, $continue=true, $feedback=true) {
1131 if (strtolower(get_class($table)) != 'xmldbtable') {
1134 if (strtolower(get_class($key)) != 'xmldbkey') {
1137 if ($key->getType() == XMLDB_KEY_PRIMARY
) { // Prevent PRIMARY to be added (only in create table, being serious :-P)
1138 debugging('Primary Keys can be added at table create time only', DEBUG_DEVELOPER
);
1142 if(!$sqlarr = $table->getAddKeySQL($CFG->dbtype
, $CFG->prefix
, $key, false)) {
1143 return true; //Empty array = nothing to do = no error
1146 return execute_sql_arr($sqlarr, $continue, $feedback);
1150 * This function will drop the key in the table passed as arguments
1153 * @param XMLDBTable table object (just the name is mandatory)
1154 * @param XMLDBKey key object (full specs are required)
1155 * @param boolean continue to specify if must continue on error (true) or stop (false)
1156 * @param boolean feedback to specify to show status info (true) or not (false)
1157 * @return boolean true on success, false on error
1159 function drop_key($table, $key, $continue=true, $feedback=true) {
1165 if (strtolower(get_class($table)) != 'xmldbtable') {
1168 if (strtolower(get_class($key)) != 'xmldbkey') {
1171 if ($key->getType() == XMLDB_KEY_PRIMARY
) { // Prevent PRIMARY to be dropped (only in drop table, being serious :-P)
1172 debugging('Primary Keys can be deleted at table drop time only', DEBUG_DEVELOPER
);
1176 if(!$sqlarr = $table->getDropKeySQL($CFG->dbtype
, $CFG->prefix
, $key, false)) {
1177 return true; //Empty array = nothing to do = no error
1180 return execute_sql_arr($sqlarr, $continue, $feedback);
1184 * This function will rename the key in the table passed as arguments
1185 * Experimental. Shouldn't be used at all in normal installation/upgrade!
1188 * @param XMLDBTable table object (just the name is mandatory)
1189 * @param XMLDBKey key object (full specs are required)
1190 * @param string new name of the key
1191 * @param boolean continue to specify if must continue on error (true) or stop (false)
1192 * @param boolean feedback to specify to show status info (true) or not (false)
1193 * @return boolean true on success, false on error
1195 function rename_key($table, $key, $newname, $continue=true, $feedback=true) {
1199 debugging('rename_key() is one experimental feature. You must not use it in production!', DEBUG_DEVELOPER
);
1203 if (strtolower(get_class($table)) != 'xmldbtable') {
1206 if (strtolower(get_class($key)) != 'xmldbkey') {
1210 /// Check newname isn't empty
1212 debugging('New name for key ' . $table->getName() . '->' . $key->getName() .
1213 ' is empty! Rename skipped', DEBUG_DEVELOPER
);
1214 return true; //Key doesn't exist, nothing to do
1217 if(!$sqlarr = $table->getRenameKeySQL($CFG->dbtype
, $CFG->prefix
, $key, $newname, false)) {
1218 debugging('Some DBs do not support key renaming (MySQL, PostgreSQL, MsSQL). Rename skipped', DEBUG_DEVELOPER
);
1219 return true; //Empty array = nothing to do = no error
1222 return execute_sql_arr($sqlarr, $continue, $feedback);
1226 * This function will create the index in the table passed as arguments
1227 * Before creating the index, the function will check it doesn't exists
1230 * @param XMLDBTable table object (just the name is mandatory)
1231 * @param XMLDBIndex index object (full specs are required)
1232 * @param boolean continue to specify if must continue on error (true) or stop (false)
1233 * @param boolean feedback to specify to show status info (true) or not (false)
1234 * @return boolean true on success, false on error
1236 function add_index($table, $index, $continue=true, $feedback=true) {
1242 if (strtolower(get_class($table)) != 'xmldbtable') {
1245 if (strtolower(get_class($index)) != 'xmldbindex') {
1249 /// Check index doesn't exist
1250 if (index_exists($table, $index)) {
1251 debugging('Index ' . $table->getName() . '->' . $index->getName() .
1252 ' already exists. Create skipped', DEBUG_DEVELOPER
);
1253 return true; //Index exists, nothing to do
1256 if(!$sqlarr = $table->getAddIndexSQL($CFG->dbtype
, $CFG->prefix
, $index, false)) {
1257 return true; //Empty array = nothing to do = no error
1260 return execute_sql_arr($sqlarr, $continue, $feedback);
1264 * This function will drop the index in the table passed as arguments
1265 * Before dropping the index, the function will check it exists
1268 * @param XMLDBTable table object (just the name is mandatory)
1269 * @param XMLDBIndex index object (full specs are required)
1270 * @param boolean continue to specify if must continue on error (true) or stop (false)
1271 * @param boolean feedback to specify to show status info (true) or not (false)
1272 * @return boolean true on success, false on error
1274 function drop_index($table, $index, $continue=true, $feedback=true) {
1280 if (strtolower(get_class($table)) != 'xmldbtable') {
1283 if (strtolower(get_class($index)) != 'xmldbindex') {
1287 /// Check index exists
1288 if (!index_exists($table, $index)) {
1289 debugging('Index ' . $table->getName() . '->' . $index->getName() .
1290 ' does not exist. Delete skipped', DEBUG_DEVELOPER
);
1291 return true; //Index doesn't exist, nothing to do
1294 if(!$sqlarr = $table->getDropIndexSQL($CFG->dbtype
, $CFG->prefix
, $index, false)) {
1295 return true; //Empty array = nothing to do = no error
1298 return execute_sql_arr($sqlarr, $continue, $feedback);
1302 * This function will rename the index in the table passed as arguments
1303 * Before renaming the index, the function will check it exists
1304 * Experimental. Shouldn't be used at all!
1307 * @param XMLDBTable table object (just the name is mandatory)
1308 * @param XMLDBIndex index object (full specs are required)
1309 * @param string new name of the index
1310 * @param boolean continue to specify if must continue on error (true) or stop (false)
1311 * @param boolean feedback to specify to show status info (true) or not (false)
1312 * @return boolean true on success, false on error
1314 function rename_index($table, $index, $newname, $continue=true, $feedback=true) {
1318 debugging('rename_index() is one experimental feature. You must not use it in production!', DEBUG_DEVELOPER
);
1322 if (strtolower(get_class($table)) != 'xmldbtable') {
1325 if (strtolower(get_class($index)) != 'xmldbindex') {
1329 /// Check index exists
1330 if (!index_exists($table, $index)) {
1331 debugging('Index ' . $table->getName() . '->' . $index->getName() .
1332 ' does not exist. Rename skipped', DEBUG_DEVELOPER
);
1333 return true; //Index doesn't exist, nothing to do
1336 /// Check newname isn't empty
1338 debugging('New name for index ' . $table->getName() . '->' . $index->getName() .
1339 ' is empty! Rename skipped', DEBUG_DEVELOPER
);
1340 return true; //Index doesn't exist, nothing to do
1343 if(!$sqlarr = $table->getRenameIndexSQL($CFG->dbtype
, $CFG->prefix
, $index, $newname, false)) {
1344 debugging('Some DBs do not support index renaming (MySQL). Rename skipped', DEBUG_DEVELOPER
);
1345 return true; //Empty array = nothing to do = no error
1348 return execute_sql_arr($sqlarr, $continue, $feedback);
1351 /* trys to change default db encoding to utf8, if empty db
1353 function change_db_encoding() {
1355 // try forcing utf8 collation, if mysql db and no tables present
1356 if (($CFG->dbfamily
=='mysql') && !$db->Metatables()) {
1357 $SQL = 'ALTER DATABASE '.$CFG->dbname
.' CHARACTER SET utf8';
1358 execute_sql($SQL, false); // silent, if it fails it fails
1359 if (setup_is_unicodedb()) {
1360 configure_dbconnection();