### Eclipse Workspace Patch 1.0
#P moodle
Index: mod/hotpot/restorelib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/hotpot/restorelib.php,v
retrieving revision 1.24
diff -u -r1.24 restorelib.php
--- mod/hotpot/restorelib.php	4 Jan 2007 23:38:26 -0000	1.24
+++ mod/hotpot/restorelib.php	15 May 2008 21:11:28 -0000
@@ -298,8 +298,8 @@
     // maintain a cache of info on table columns
     static $table_columns = array();
     if (empty($table_columns[$table])) {
-        global $CFG, $db; 
-        $table_columns[$table] = $db->MetaColumns("$CFG->prefix$table");
+        global $CFG, $DB; 
+        $table_columns[$table] = $DB->get_columns($table);
     }
 
     // get values for fields in this record
Index: mod/hotpot/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/hotpot/lib.php,v
retrieving revision 1.88
diff -u -r1.88 lib.php
--- mod/hotpot/lib.php	1 May 2008 22:03:15 -0000	1.88
+++ mod/hotpot/lib.php	15 May 2008 21:11:28 -0000
@@ -2191,7 +2191,7 @@
     hotpot_add_response($attempt, $question, $response);
 }
 function hotpot_add_response(&$attempt, &$question, &$response) {
-    global $db, $next_url;
+    global $DB, $next_url;
 
     $loopcount = 1;
 
@@ -2206,7 +2206,7 @@
         if (!$question->id = get_field('hotpot_questions', 'id', 'hotpot', $attempt->hotpot, 'md5key', $question->md5key, 'name', $question->name)) {
             // add question record
             if (!$question->id = insert_record('hotpot_questions', $question)) {
-                print_error("Could not add question record (attempt_id=$attempt->id): ".$db->ErrorMsg(), '', $next_url);
+                print_error("Could not add question record (attempt_id=$attempt->id): ".$DB->get_last_error(), '', $next_url);
             }
         }
 
@@ -2231,7 +2231,7 @@
 
             // add response record
             if(!$response->id = insert_record('hotpot_responses', $response)) {
-                print_error("Could not add response record (attempt_id=$attempt->id, question_id=$question->id): ".$db->ErrorMsg(), '', $next_url);
+                print_error("Could not add response record (attempt_id=$attempt->id, question_id=$question->id): ".$DB->get_last_error(), '', $next_url);
             }
 
             // we can stop looping now
@@ -2384,8 +2384,8 @@
 
             // try and add the new string record
             if (!$id = insert_record('hotpot_strings', $record)) {
-                global $db;
-                print_error("Could not add string record for '".htmlspecialchars($str)."': ".$db->ErrorMsg());
+                global $DB;
+                print_error("Could not add string record for '".htmlspecialchars($str)."': ".$DB->get_last_error());
             }
         }
     }
Index: mod/hotpot/view.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/hotpot/view.php,v
retrieving revision 1.42
diff -u -r1.42 view.php
--- mod/hotpot/view.php	4 Apr 2008 02:54:42 -0000	1.42
+++ mod/hotpot/view.php	15 May 2008 21:11:29 -0000
@@ -146,7 +146,7 @@
 
                 $attemptid = hotpot_add_attempt($hotpot->id);
                 if (! is_numeric($attemptid)) {
-                    print_error('Could not insert attempt record: '.$db->ErrorMsg);
+                    print_error('Could not insert attempt record: '.$DB->get_last_error());
                 }
             }
             $hp->adjust_media_urls();
Index: mod/hotpot/attempt.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/hotpot/attempt.php,v
retrieving revision 1.20
diff -u -r1.20 attempt.php
--- mod/hotpot/attempt.php	4 Apr 2008 02:54:42 -0000	1.20
+++ mod/hotpot/attempt.php	15 May 2008 21:11:25 -0000
@@ -6,7 +6,7 @@
 
     // get attempt, hotpot, course and course_module records
     if (! $attempt = get_record("hotpot_attempts", "id", $attemptid)) {
-        print_error("Hot Potatoes attempt record $attemptid could not be accessed: ".$db->ErrorMsg());
+        print_error("Hot Potatoes attempt record $attemptid could not be accessed: ".$DB->get_last_error());
     }
     if ($attempt->userid != $USER->id) {
         print_error("User ID is incorrect");
@@ -82,7 +82,7 @@
             $attempt->id = insert_record("hotpot_attempts", $attempt);
 
             if (empty($attempt->id)) {
-                print_error("Could not insert attempt record: ".$db->ErrorMsg(), '', $next_url);
+                print_error("Could not insert attempt record: ".$DB->get_last_error(), '', $next_url);
             }
 
             // add attempt details record, if necessary
@@ -91,7 +91,7 @@
                 $details->attempt = $attempt->id;
                 $details->details = $attempt->details;
                 if (! insert_record("hotpot_details", $details, false)) {
-                    print_error("Could not insert attempt details record: ".$db->ErrorMsg(), '', $next_url);
+                    print_error("Could not insert attempt details record: ".$DB->get_last_error(), '', $next_url);
                 }
             }
         } else {
@@ -112,7 +112,7 @@
 
     // update the attempt record
     if (! update_record("hotpot_attempts", $attempt)) {
-        print_error("Could not update attempt record: ".$db->ErrorMsg(), '', $next_url);
+        print_error("Could not update attempt record: ".$DB->get_last_error(), '', $next_url);
     }
 
     // update grades for this user
@@ -134,7 +134,7 @@
             $details->attempt = $attempt->id;
             $details->details = $attempt->details;
             if (! insert_record("hotpot_details", $details)) {
-                print_error("Could not insert attempt details record: ".$db->ErrorMsg(), '', $next_url);
+                print_error("Could not insert attempt details record: ".$DB->get_last_error(), '', $next_url);
             }
         }
     }
Index: mod/hotpot/index.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/hotpot/index.php,v
retrieving revision 1.30
diff -u -r1.30 index.php
--- mod/hotpot/index.php	2 May 2008 04:37:06 -0000	1.30
+++ mod/hotpot/index.php	15 May 2008 21:11:25 -0000
@@ -163,7 +163,7 @@
                             if ($attempt->details) {
                                 hotpot_add_attempt_details($attempt);
                                 if (! update_record('hotpot_attempts', $attempt)) {
-                                    print_error("Could not update attempt record: ".$db->ErrorMsg(), '', $next_url);
+                                    print_error("Could not update attempt record: ".$DB->get_last_error(), '', $next_url);
                                 }
                             }
                             $attemptcount++;
Index: blocks/admin/block_admin.php
===================================================================
RCS file: /cvsroot/moodle/moodle/blocks/admin/block_admin.php,v
retrieving revision 1.109
diff -u -r1.109 block_admin.php
--- blocks/admin/block_admin.php	2 May 2008 06:07:51 -0000	1.109
+++ blocks/admin/block_admin.php	15 May 2008 21:10:40 -0000
@@ -8,7 +8,7 @@
 
     function get_content() {
 
-        global $CFG, $USER, $SITE, $COURSE;
+        global $CFG, $USER, $SITE, $COURSE, $DB;
 
         if ($this->content !== NULL) {
             return $this->content;
@@ -30,7 +30,7 @@
             if ($COURSE->id == $this->instance->pageid) {
                 $course = $COURSE;
             } else {
-                $course = get_record('course', 'id', $this->instance->pageid);
+                $course = $DB->get_record('course', array('id'=>$this->instance->pageid));
             }
         } else {
             $context = get_context_instance(CONTEXT_SYSTEM);
Index: admin/xmldb/index.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/index.php,v
retrieving revision 1.11
diff -u -r1.11 index.php
--- admin/xmldb/index.php	2 May 2008 04:37:03 -0000	1.11
+++ admin/xmldb/index.php	15 May 2008 21:10:30 -0000
@@ -28,23 +28,21 @@
 /// all the actions supported will be launched.
 
 /// Add required XMLDB constants
-    require_once('../../lib/xmldb/classes/XMLDBConstants.php');
+    require_once('../../lib/xmldb/XMLDBConstants.php');
 
 /// Add required XMLDB action classes
     require_once('actions/XMLDBAction.class.php');
 
-/// Add main XMLDB Generator
-    require_once('../../lib/xmldb/classes/generators/XMLDBGenerator.class.php');
 
 /// Add required XMLDB DB classes
-    require_once('../../lib/xmldb/classes/XMLDBObject.class.php');
-    require_once('../../lib/xmldb/classes/XMLDBFile.class.php');
-    require_once('../../lib/xmldb/classes/XMLDBStructure.class.php');
-    require_once('../../lib/xmldb/classes/XMLDBTable.class.php');
-    require_once('../../lib/xmldb/classes/XMLDBField.class.php');
-    require_once('../../lib/xmldb/classes/XMLDBKey.class.php');
-    require_once('../../lib/xmldb/classes/XMLDBIndex.class.php');
-    require_once('../../lib/xmldb/classes/XMLDBStatement.class.php');
+    require_once('../../lib/xmldb/XMLDBObject.class.php');
+    require_once('../../lib/xmldb/XMLDBFile.class.php');
+    require_once('../../lib/xmldb/XMLDBStructure.class.php');
+    require_once('../../lib/xmldb/XMLDBTable.class.php');
+    require_once('../../lib/xmldb/XMLDBField.class.php');
+    require_once('../../lib/xmldb/XMLDBKey.class.php');
+    require_once('../../lib/xmldb/XMLDBIndex.class.php');
+    require_once('../../lib/xmldb/XMLDBStatement.class.php');
 
 /// Add Moodle config script (this is loaded AFTER all the rest
 /// of classes because it starts the SESSION and classes to be
@@ -59,12 +57,6 @@
 /// Add other used libraries
     require_once($CFG->libdir . '/xmlize.php');
 
-/// Add all the available SQL generators
-    $generators = get_list_of_plugins('lib/xmldb/classes/generators');
-    foreach($generators as $generator) {
-        require_once ('../../lib/xmldb/classes/generators/' . $generator . '/' . $generator . '.class.php');
-    }
-
 /// Handle session data
     global $XMLDB;
 /// The global SESSION object where everything will happen
Index: admin/multilangupgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/multilangupgrade.php,v
retrieving revision 1.8
diff -u -r1.8 multilangupgrade.php
--- admin/multilangupgrade.php	10 Apr 2008 03:44:09 -0000	1.8
+++ admin/multilangupgrade.php	15 May 2008 21:10:30 -0000
@@ -24,7 +24,7 @@
 }
 
 
-if (!$tables = $db->Metatables() ) {    // No tables yet at all.
+if (!$tables = $DB->get_tables() ) {    // No tables yet at all.
     print_error('notables', 'debug');
 }
 
@@ -38,29 +38,28 @@
 
 echo '<strong>Progress:</strong>';
 $i = 0;
-$skiptables = array($CFG->prefix.'config', $CFG->prefix.'user_students', $CFG->prefix.'user_teachers');//, $CFG->prefix.'sessions2');
+$skiptables = array('config', 'user_students', 'user_teachers');//, 'sessions2');
 
 foreach ($tables as $table) {
-    if (($CFG->prefix && strpos($table, $CFG->prefix) !== 0)
-      or strpos($table, $CFG->prefix.'pma') === 0) { // Not our tables
+    if (strpos($table,'pma') === 0) { // Not our tables
         continue;
     }
     if (in_array($table, $skiptables)) { // Don't process these
         continue;
     }
-    if ($columns = $db->MetaColumns($table, false)) {
+    $fulltable = $DB->get_prefix().$table;
+    if ($columns = $DB->get_columns($table)) {
         if (!array_key_exists('id', $columns) and !array_key_exists('ID', $columns)) {
             continue; // moodle tables have id
         }
         foreach ($columns as $column => $data) {
             if (in_array($data->type, array('text','mediumtext','longtext','varchar'))) {  // Text stuff only
                 // first find candidate records
-                $rs = get_recordset_sql("SELECT id, $column FROM $table WHERE $column LIKE '%</lang>%' OR $column LIKE '%<span lang=%'");
-                if ($rs) {
-                    while (!$rs->EOF) {
-                        $text = $rs->fields[$column];
-                        $id   = $rs->fields['id'];
-
+                $sql = "SELECT id, $column FROM $fulltable WHERE $column LIKE '%</lang>%' OR $column LIKE '%<span lang=%'";
+                if ($rs = $DB->get_recordset_sql($sql)) {
+                    foreach ($rs as $data) {
+                        $text = $data->$column;
+                        $id   = $data->id;
                         if ($i % 600 == 0) {
                             echo '<br />';
                         }
@@ -68,7 +67,6 @@
                             echo '.';
                         }
                         $i++;
-                        $rs->MoveNext();
 
                         if (empty($text) or is_numeric($text)) {
                             continue; // nothing to do
@@ -82,11 +80,10 @@
                         }
 
                         if ($newtext != $text) {
-                            $newtext = addslashes($newtext);
-                            execute_sql("UPDATE $table SET $column='$newtext' WHERE id=$id", false);
+                            $DB->execute("UPDATE $fulltable SET $column=? WHERE id=?", array($newtext, $id));
                         }
                     }
-                    rs_close($rs);
+                    $rs->close();
                 }
             }
         }
Index: admin/cliupgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/cliupgrade.php,v
retrieving revision 1.11
diff -u -r1.11 cliupgrade.php
--- admin/cliupgrade.php	2 May 2008 09:47:20 -0000	1.11
+++ admin/cliupgrade.php	15 May 2008 21:10:28 -0000
@@ -860,16 +860,16 @@
         /// Both old .sql files and new install.xml are supported
         /// But we prioritise install.xml (XMLDB) if present
 
-        change_db_encoding(); // first try to change db encoding to utf8
-
-        if (!setup_is_unicodedb()) {
-            // If could not convert successfully, throw error, and prevent installation
-            console_write(STDERR,'unicoderequired', 'admin');
+        if (!$DB->setup_is_unicodedb()) {
+            if (!$DB->change_db_encoding()) {
+                // If could not convert successfully, throw error, and prevent installation
+                console_write(STDERR,'unicoderequired', 'admin');
+            }
         }
 
         $status = false;
         if (file_exists("$CFG->libdir/db/install.xml")) {
-            $status = install_from_xmldb_file("$CFG->libdir/db/install.xml"); //New method
+            $status = $DB->get_manager()->install_from_xmldb_file("$CFG->libdir/db/install.xml"); //New method
         } else {
             console_write(STDERR,"Error: Your database ($CFG->dbtype) is not yet fully supported by Moodle or install.xml is not present.  See the lib/db directory.",'',false);
         }
Index: admin/cron.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/cron.php,v
retrieving revision 1.138
diff -u -r1.138 cron.php
--- admin/cron.php	1 May 2008 05:49:35 -0000	1.138
+++ admin/cron.php	15 May 2008 21:10:29 -0000
@@ -36,7 +36,7 @@
 
 /// Extra debugging (set in config.php)
     if (!empty($CFG->showcronsql)) {
-        $db->debug = true;
+        $DB->set_debug(true);
     }
     if (!empty($CFG->showcrondebugging)) {
         $CFG->debug = DEBUG_DEVELOPER;
Index: admin/index.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/index.php,v
retrieving revision 1.312
diff -u -r1.312 index.php
--- admin/index.php	2 May 2008 09:47:20 -0000	1.312
+++ admin/index.php	15 May 2008 21:10:30 -0000
@@ -61,14 +61,6 @@
         print_error('phpvaron', 'debug', '', array('file_uploads', $documentationlink));
     }
 
-    if (empty($CFG->prefix) && $CFG->dbfamily != 'mysql') {  //Enforce prefixes for everybody but mysql
-        print_error('prefixcannotbeempty', 'debug', '', array($CFG->prefix, $CFG->dbtype));
-    }
-
-    if ($CFG->dbfamily == 'oracle' && strlen($CFG->prefix) > 2) { //Max prefix length for Oracle is 2cc
-        print_error('prefixlimit', 'debug', '', $CFG->prefix);
-    }
-
 /// Check that config.php has been edited
 
     if ($CFG->wwwroot == "http://example.com/moodle") {
@@ -103,8 +95,7 @@
     }
 
 /// Check if the main tables have been installed yet or not.
-
-    if (! $tables = $db->Metatables() ) {    // No tables yet at all.
+    if (!$tables = $DB->get_tables() ) {    // No tables yet at all.
         $maintables = false;
 
     } else {                                 // Check for missing main tables
@@ -113,7 +104,7 @@
                          "course_sections", "log", "log_display", "modules",
                          "user");
         foreach ($mtables as $mtable) {
-            if (!in_array($CFG->prefix.$mtable, $tables)) {
+            if (!in_array($mtable, $tables)) {
                 $maintables = false;
                 break;
             }
@@ -164,20 +155,21 @@
         $CFG->debug = $origdebug;
         error_reporting($CFG->debug);
         upgrade_log_start();
-        $db->debug = true;
+        $DB->set_debug(true);
 
     /// Both old .sql files and new install.xml are supported
     /// But we prioritise install.xml (XMLDB) if present
 
-        change_db_encoding(); // first try to change db encoding to utf8
-        if (!setup_is_unicodedb()) {
-            // If could not convert successfully, throw error, and prevent installation
-            print_error('unicoderequired', 'admin');
+        if (!$DB->setup_is_unicodedb()) {
+            if (!$DB->change_db_encoding()) {
+                // If could not convert successfully, throw error, and prevent installation
+                print_error('unicoderequired', 'admin');
+            }
         }
 
         $status = false;
         if (file_exists("$CFG->libdir/db/install.xml")) {
-            $status = install_from_xmldb_file("$CFG->libdir/db/install.xml"); //New method
+            $status = $DB->get_manager()->install_from_xmldb_file("$CFG->libdir/db/install.xml"); //New method
         } else {
             print_error('dbnotsupport', 'debug', '', $CFG->dbtype);
         }
@@ -186,7 +178,7 @@
         set_config('unicodedb', 1);
 
     /// Continue with the instalation
-        $db->debug = false;
+        $DB->set_debug(false);
         if ($status) {
 
             /// Groups install is now in core above.
@@ -335,7 +327,7 @@
                 upgrade_language_pack();
 
                 print_heading($strdatabasechecking);
-                $db->debug=true;
+                $DB->set_debug(true);
             /// Launch the old main upgrade (if exists)
                 $status = true;
                 if (function_exists('main_upgrade')) {
@@ -345,7 +337,7 @@
                 if ($status && function_exists('xmldb_main_upgrade')) {
                     $status = xmldb_main_upgrade($CFG->version);
                 }
-                $db->debug=false;
+                $DB->set_debug(false);
             /// If successful, continue upgrading roles and setting everything properly
                 if ($status) {
                     if (!update_capabilities()) {
@@ -473,7 +465,7 @@
         $newsite->students = get_string("defaultcoursestudents");
         $newsite->timemodified = time();
 
-        if (!$newid = insert_record('course', $newsite)) {
+        if (!$newid = $DB->insert_record('course', $newsite)) {
             print_error('cannotsetupsite', 'error');
         }
         // make sure course context exists
@@ -486,7 +478,7 @@
         $cat = new object();
         $cat->name = get_string('miscellaneous');
         $cat->depth = 1;
-        if (!$catid = insert_record('course_categories', $cat)) {
+        if (!$catid = $DB->insert_record('course_categories', $cat)) {
             print_error('cannotsetupcategory', 'error');
         }
         // make sure category context exists
@@ -505,10 +497,10 @@
         blocks_repopulate_page($page);
 
         //add admin_tree block to site if not already present
-        if ($admintree = get_record('block', 'name', 'admin_tree')) {
+        if ($admintree = $DB->get_record('block', array('name'=>'admin_tree'))) {
             $page = page_create_object(PAGE_COURSE_VIEW, SITEID);
             blocks_execute_action($page, blocks_get_by_page($page), 'add', (int)$admintree->id, false, false);
-            if ($admintreeinstance = get_record('block_instance', 'pagetype', $page->type, 'pageid', SITEID, 'blockid', $admintree->id)) {
+            if ($admintreeinstance = $DB->get_record('block_instance', array('pagetype'=>$page->type, 'pageid'=>SITEID, 'blockid'=>$admintree->id))) {
                 blocks_execute_action($page, blocks_get_by_page($page), 'moveleft', $admintreeinstance, false, false);
             }
         }
@@ -522,7 +514,7 @@
     }
 
 /// Check if the guest user exists.  If not, create one.
-    if (! record_exists("user", "username", "guest")) {
+    if (!$DB->record_exists('user', array('username'=>'guest'))) {
         if (! $guest = create_guest_record()) {
             notify("Could not create guest user record !!!");
         }
Index: admin/timezone.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/timezone.php,v
retrieving revision 1.9
diff -u -r1.9 timezone.php
--- admin/timezone.php	2 May 2008 04:37:03 -0000	1.9
+++ admin/timezone.php	15 May 2008 21:10:30 -0000
@@ -2,7 +2,12 @@
 
     require_once('../config.php');
 
-    $zone = optional_param('zone', '', PARAM_PATH); //not a path, but it looks like it anyway
+    $zone = optional_param('zone', '', PARAM_RAW);
+
+    if (!is_numeric($zone)) {
+         //not a path, but it looks like it anyway
+         $zone = clean_param($zone, PARAM_PATH);
+    }    
 
     require_login();
 
@@ -17,24 +22,26 @@
 
     print_heading("");
 
-    if (!empty($zone) and confirm_sesskey()) {
-        $db->debug = true;
+    if (data_submitted() and !empty($zone) and confirm_sesskey()) {
         echo "<center>";
-        execute_sql("UPDATE {$CFG->prefix}user SET timezone = '$zone'");
-        $db->debug = false;
+        $DB->execute("UPDATE {user} SET timezone = ?", array($zone));
         echo "</center>";
 
         $USER->timezone = $zone;
+        $current = $zone;
+        notify('Timezone of all users changed', 'notifysuccess');
+    } else {
+        $current = 99;
     }
 
     require_once($CFG->dirroot.'/calendar/lib.php');
     $timezones = get_list_of_timezones();
 
-    echo '<center><form action="timezone.php" method="get">';
+    echo '<center><form action="timezone.php" method="post">';
     echo "$strusers ($strall): ";
-    choose_from_menu ($timezones, "zone", 99, get_string("serverlocaltime"), "", "99");
+    choose_from_menu ($timezones, "zone", $current, get_string("serverlocaltime"), "", "99");
     echo "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />";
-    echo "<input type=\"submit\" value=\"$strsavechanges\" />";
+    echo '<input type="submit" value="'.s($strsavechanges).'" />';
     echo "</form></center>";
 
     print_footer();
Index: admin/innodb.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/innodb.php,v
retrieving revision 1.9
diff -u -r1.9 innodb.php
--- admin/innodb.php	2 May 2008 04:37:02 -0000	1.9
+++ admin/innodb.php	15 May 2008 21:10:30 -0000
@@ -1,43 +1,44 @@
 <?php
 
-   require_once('../config.php');
-   require_once($CFG->libdir.'/adminlib.php');
+    require_once('../config.php');
+    require_once($CFG->libdir.'/adminlib.php');
 
-   admin_externalpage_setup('toinodb');
+    admin_externalpage_setup('toinodb');
 
-   $confirm = optional_param('confirm', 0, PARAM_BOOL);
+    $confirm = optional_param('confirm', 0, PARAM_BOOL);
 
-   require_login();
+    require_login();
 
-   require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
+    require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
 
-   admin_externalpage_print_header();
-   print_heading('Convert all MySQL tables from MYISAM to InnoDB');
+    admin_externalpage_print_header();
+    print_heading('Convert all MySQL tables from MYISAM to InnoDB');
 
-   if ($CFG->dbfamily != 'mysql') {
+    if ($CFG->dbfamily != 'mysql') {
         notice('This function is for MySQL databases only!', 'index.php');
-   }
+    }
 
-   if (data_submitted() and $confirm and confirm_sesskey()) {
+    if (data_submitted() and $confirm and confirm_sesskey()) {
 
-       notify('Please be patient and wait for this to complete...', 'notifysuccess');
+        notify('Please be patient and wait for this to complete...', 'notifysuccess');
 
-       if ($tables = $db->MetaTables()) {
-           $db->debug = true;
-           foreach ($tables as $table) {
-               execute_sql("ALTER TABLE $table TYPE=INNODB; ");
-           }
-           $db->debug = false;
-       }
-       notify('... done.', 'notifysuccess');
-       print_continue('index.php');
-       admin_externalpage_print_footer();
-
-   } else {
-       $optionsyes = array('confirm'=>'1', 'sesskey'=>sesskey());
-       notice_yesno('Are you sure you want convert all your tables to the InnoDB format?',
-                    'innodb.php', 'index.php', $optionsyes, NULL, 'post', 'get');
-       admin_externalpage_print_footer();
-   }
+        if ($tables = $DB->get_tables()) {
+            $DB->set_debug(true);
+            foreach ($tables as $table) {
+                $fulltable = $DB->get_prefix().$table;
+                $DB->change_database_structure("ALTER TABLE $fulltable TYPE=INNODB");
+            }
+            $DB->set_debug(false);
+        }
+        notify('... done.', 'notifysuccess');
+        print_continue('index.php');
+        admin_externalpage_print_footer();
+
+    } else {
+        $optionsyes = array('confirm'=>'1', 'sesskey'=>sesskey());
+        notice_yesno('Are you sure you want convert all your tables to the InnoDB format?',
+                     'innodb.php', 'index.php', $optionsyes, NULL, 'post', 'get');
+        admin_externalpage_print_footer();
+    }
 
 ?>
Index: admin/replace.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/replace.php,v
retrieving revision 1.11
diff -u -r1.11 replace.php
--- admin/replace.php	10 Apr 2008 03:44:09 -0000	1.11
+++ admin/replace.php	15 May 2008 21:10:30 -0000
@@ -34,16 +34,16 @@
 
 print_simple_box_start('center');
 
-if (!db_replace($search, $replace)) {
+if (!db_replace(stripslashes($search), stripslashes($replace))) {
     print_error('erroroccur', debug);
 }
 
 print_simple_box_end();
 
 /// Rebuild course cache which might be incorrect now
-notify('Rebuilding course cache...');
+notify('Rebuilding course cache...', 'notifysuccess');
 rebuild_course_cache();
-notify('...finished');
+notify('...finished', 'notifysuccess');
 
 print_continue('index.php');
 
Index: mod/glossary/edit.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/glossary/edit.php,v
retrieving revision 1.79
diff -u -r1.79 edit.php
--- mod/glossary/edit.php	4 Apr 2008 02:54:40 -0000	1.79
+++ mod/glossary/edit.php	15 May 2008 21:11:25 -0000
@@ -157,7 +157,7 @@
 
         $toform = new object();
 
-        if ($categoriesarr = get_records_menu("glossary_entries_categories", "entryid", $e, '', 'id, categoryid')){
+        if ($categoriesarr = $DB->get_records_menu("glossary_entries_categories", array("entryid"=>$e), '', 'id, categoryid')){
             $toform->categories = array_values($categoriesarr);
         } else {
             $toform->categories = array(0);
@@ -181,7 +181,7 @@
             die;
         }
 
-        if ( $aliases = get_records_menu("glossary_alias", "entryid", $e, '', 'id, alias') ) {
+        if ( $aliases = $DB->get_records_menu("glossary_alias", array("entryid"=>$e), '', 'id, alias') ) {
             $toform->aliases = implode("\n", $aliases) . "\n";
         }
         $mform->set_data($toform);
Index: mod/glossary/edit_form.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/glossary/edit_form.php,v
retrieving revision 1.8
diff -u -r1.8 edit_form.php
--- mod/glossary/edit_form.php	23 Nov 2007 22:15:09 -0000	1.8
+++ mod/glossary/edit_form.php	15 May 2008 21:11:25 -0000
@@ -5,7 +5,7 @@
 
     function definition() {
 
-        global $CFG, $COURSE;
+        global $CFG, $COURSE, $DB;
         $mform    =& $this->_form;
 
         $glossary =& $this->_customdata['glossary'];
@@ -29,7 +29,7 @@
         $mform->addElement('format');
 
         $categories = array();
-        if ($categories = get_records_menu('glossary_categories', 'glossaryid', $glossary->id, 'name ASC', 'id, name')){
+        if ($categories = $DB->get_records_menu('glossary_categories', array('glossaryid'=>$glossary->id), 'name ASC', 'id, name')){
             $categories = array(0 => get_string('notcategorised', 'glossary')) + $categories;
         } else {
             $categories = array(0 => get_string('notcategorised', 'glossary'));
Index: lib/grade/lib_wrapper.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/grade/lib_wrapper.php,v
retrieving revision 1.2
diff -u -r1.2 lib_wrapper.php
--- lib/grade/lib_wrapper.php	15 Nov 2007 06:44:27 -0000	1.2
+++ lib/grade/lib_wrapper.php	15 May 2008 21:11:22 -0000
@@ -24,6 +24,7 @@
 ///////////////////////////////////////////////////////////////////////////
 
 class grade_lib_wrapper {
+/*
     function get_records_sql($sql, $limitfrom='', $limitnum='') {
         return get_records_sql($sql, $limitfrom, $limitnum);
     }
@@ -107,7 +108,7 @@
     function rs_close(&$rs) {
         return;
     }
-    
+*/    
     function get_coursemodule_from_instance($modulename, $instance, $courseid=0) {
         return get_coursemodule_from_instance($modulename, $instance, $courseid);
     }
Index: lib/grade/grade_item.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/grade/grade_item.php,v
retrieving revision 1.169
diff -u -r1.169 grade_item.php
--- lib/grade/grade_item.php	4 Apr 2008 02:54:33 -0000	1.169
+++ lib/grade/grade_item.php	15 May 2008 21:11:22 -0000
@@ -774,10 +774,12 @@
      * @return void
      */
     function force_regrading() {
+        global $DB;
         $this->needsupdate = 1;
         //mark this item and course item only - categories and calculated items are always regraded
-        $wheresql = "(itemtype='course' OR id={$this->id}) AND courseid={$this->courseid}";
-        set_field_select('grade_items', 'needsupdate', 1, $wheresql);
+        $wheresql = "(itemtype='course' OR id=?) AND courseid=?";
+        $params   = array($this->id, $this->courseid);
+        $DB->set_field_select('grade_items', 'needsupdate', 1, $wheresql, $params);
     }
 
     /**
Index: lib/xmldb/classes/XMLDBField.class.php
===================================================================
RCS file: lib/xmldb/classes/XMLDBField.class.php
diff -N lib/xmldb/classes/XMLDBField.class.php
--- lib/xmldb/classes/XMLDBField.class.php	2 Jan 2008 16:49:11 -0000	1.14
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,912 +0,0 @@
-<?php // $Id: XMLDBField.class.php,v 1.14 2008/01/02 16:49:11 stronk7 Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class represent one XMLDB Field
-
-class XMLDBField extends XMLDBObject {
-
-    var $type;
-    var $length;
-    var $unsigned;
-    var $notnull;
-    var $default;
-    var $sequence;
-    var $enum;
-    var $enumvalues;
-    var $decimals;
-
-    /**
-     * Creates one new XMLDBField
-     */
-    function XMLDBField($name) {
-        parent::XMLDBObject($name);
-        $this->type = NULL;
-        $this->length = NULL;
-        $this->unsigned = true;
-        $this->notnull = false;
-        $this->default = NULL;
-        $this->sequence = false;
-        $this->enum = false;
-        $this->enumvalues = NULL;
-        $this->decimals = NULL;
-    }
-
-    /**
-     * Set all the attributes of one XMLDBField
-     *
-     * @param string type XMLDB_TYPE_INTEGER, XMLDB_TYPE_NUMBER, XMLDB_TYPE_CHAR, XMLDB_TYPE_TEXT, XMLDB_TYPE_BINARY
-     * @param string precision length for integers and chars, two-comma separated numbers for numbers and 'small', 'medium', 'big' for texts and binaries
-     * @param string unsigned XMLDB_UNSIGNED or null (or false)
-     * @param string notnull XMLDB_NOTNULL or null (or false)
-     * @param string sequence XMLDB_SEQUENCE or null (or false)
-     * @param string enum XMLDB_ENUM or null (or false)
-     * @param array enumvalues an array of possible values if XMLDB_ENUM is set
-     * @param string default meaningful default o null (or false)
-     */
-    function setAttributes($type, $precision=null, $unsigned=null, $notnull=null, $sequence=null, $enum=null, $enumvalues=null, $default=null, $previous=null) {
-        $this->type = $type;
-    /// Try to split the precision into length and decimals and apply
-    /// each one as needed
-        $precisionarr = explode(',', $precision);
-        if (isset($precisionarr[0])) {
-            $this->length = trim($precisionarr[0]);
-        }
-        if (isset($precisionarr[1])) {
-            $this->decimals = trim($precisionarr[1]);
-        }
-        $this->precision = $type;
-        $this->unsigned = !empty($unsigned) ? true : false;
-        $this->notnull = !empty($notnull) ? true : false;
-        $this->sequence = !empty($sequence) ? true : false;
-        $this->enum = !empty($enum) ? true : false;
-    /// Accept both quoted and non-quoted vales (quoting them)a
-        if (is_array($enumvalues)) {
-            $this->enumvalues = array();
-            foreach ($enumvalues as $value) {
-            /// trim each value quotes
-                $value = trim($value, "'");
-            /// add them back
-                $value = "'" . $value . "'";
-                $this->enumvalues[] = $value;
-            }
-        }
-        $this->setDefault($default);
-
-        $this->previous = $previous;
-    }
-
-    /**
-     * Get the type
-     */
-    function getType() {
-        return $this->type;
-    }
-
-    /**
-     * Get the length
-     */
-    function getLength() {
-        return $this->length;
-    }
-
-    /**
-     * Get the decimals
-     */
-    function getDecimals() {
-        return $this->decimals;
-    }
-
-    /**
-     * Get the notnull
-     */
-    function getNotNull() {
-        return $this->notnull;
-    }
-
-    /**
-     * Get the unsigned
-     */
-    function getUnsigned() {
-        return $this->unsigned;
-    }
-
-    /**
-     * Get the sequence
-     */
-    function getSequence() {
-        return $this->sequence;
-    }
-
-    /**
-     * Get the enum
-     */
-    function getEnum() {
-        return $this->enum;
-    }
-
-    /**
-     * Get the enumvalues
-     */
-    function getEnumValues() {
-        return $this->enumvalues;
-    }
-
-    /**
-     * Get the default
-     */
-    function getDefault() {
-        return $this->default;
-    }
-
-    /**
-     * Set the field type
-     */
-    function setType($type) {
-        $this->type = $type;
-    }
-
-    /**
-     * Set the field length
-     */
-    function setLength($length) {
-        $this->length = $length;
-    }
-
-    /**
-     * Set the field decimals
-     */
-    function setDecimals($decimals) {
-        $this->decimals = $decimals;
-    }
-
-    /**
-     * Set the field unsigned
-     */
-    function setUnsigned($unsigned=true) {
-        $this->unsigned = $unsigned;
-    }
-
-    /**
-     * Set the field notnull
-     */
-    function setNotNull($notnull=true) {
-        $this->notnull = $notnull;
-    }
-
-    /**
-     * Set the field sequence
-     */
-    function setSequence($sequence=true) {
-        $this->sequence = $sequence;
-    }
-
-    /**
-     * Set the field enum
-     */
-    function setEnum($enum=true) {
-        $this->enum = $enum;
-    }
-
-    /**
-     * Set the field enumvalues, quoting unquoted values
-     */
-    function setEnumValues($enumvalues) {
-        if (is_array($enumvalues)) {
-            $this->enumvalues = array();
-            foreach ($enumvalues as $value) {
-            /// trim each value quotes
-                $value = trim($value, "'");
-            /// add them back
-                $value = "'" . $value . "'";
-                $this->enumvalues[] = $value;
-            }
-        }
-    }
-
-    /**
-     * Set the field default
-     */
-    function setDefault($default) {
-    /// Check, warn and auto-fix '' (empty) defaults for CHAR NOT NULL columns, changing them
-    /// to NULL so XMLDB will apply the proper default
-        if ($this->type == XMLDB_TYPE_CHAR && $this->notnull && $default === '') {
-            $this->errormsg = 'XMLDB has detected one CHAR NOT NULL column (' . $this->name . ") with '' (empty string) as DEFAULT value. This type of columns must have one meaningful DEFAULT declared or none (NULL). XMLDB have fixed it automatically changing it to none (NULL). The process will continue ok and proper defaults will be created accordingly with each DB requirements. Please fix it in source (XML and/or upgrade script) to avoid this message to be displayed.";
-            $this->debug($this->errormsg);
-            $default = NULL;
-        }
-        $this->default = $default;
-    }
-
-    /**
-     * Load data from XML to the table
-     */
-    function arr2XMLDBField($xmlarr) {
-
-        $result = true;
-
-    /// Debug the table
-    /// traverse_xmlize($xmlarr);                   //Debug
-    /// print_object ($GLOBALS['traverse_array']);  //Debug
-    /// $GLOBALS['traverse_array']="";              //Debug
-
-    /// Process table attributes (name, type, length, unsigned,
-    /// notnull, sequence, enum, enumvalues, decimals, comment,
-    /// previous, next)
-        if (isset($xmlarr['@']['NAME'])) {
-            $this->name = trim($xmlarr['@']['NAME']);
-        } else {
-            $this->errormsg = 'Missing NAME attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-        if (isset($xmlarr['@']['TYPE'])) {
-        /// Check for valid type
-            $type = $this->getXMLDBFieldType(trim($xmlarr['@']['TYPE']));
-            if ($type) {
-                $this->type = $type;
-            } else {
-                $this->errormsg = 'Invalid TYPE attribute';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        } else {
-            $this->errormsg = 'Missing TYPE attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-        if (isset($xmlarr['@']['LENGTH'])) {
-            $length = trim($xmlarr['@']['LENGTH']);
-        /// Check for integer values
-            if ($this->type == XMLDB_TYPE_INTEGER ||
-                $this->type == XMLDB_TYPE_NUMBER ||
-                $this->type == XMLDB_TYPE_CHAR) {
-                if (!(is_numeric($length)&&(intval($length)==floatval($length)))) {
-                    $this->errormsg = 'Incorrect LENGTH attribute for int, number or char fields';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                } else if (!$length) {
-                    $this->errormsg = 'Zero LENGTH attribute';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            }
-        /// Check for big, medium, small to be applied to text and binary
-            if ($this->type == XMLDB_TYPE_TEXT ||
-                $this->type == XMLDB_TYPE_BINARY) {
-                if (!$length) {
-                    $length == 'big';
-                }
-                if ($length != 'big' &&
-                    $length != 'medium' &&
-                    $length != 'small') {
-                    $this->errormsg = 'Incorrect LENGTH attribute for text and binary fields (only big, medium and small allowed)';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            }
-        /// Finally, set the length
-            $this->length = $length;
-        }
-
-        if (isset($xmlarr['@']['UNSIGNED'])) {
-            $unsigned = strtolower(trim($xmlarr['@']['UNSIGNED']));
-            if ($unsigned == 'true') {
-                $this->unsigned = true;
-            } else if ($unsigned == 'false') {
-                $this->unsigned = false;
-            } else {
-                $this->errormsg = 'Incorrect UNSIGNED attribute (true/false allowed)';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        }
-
-        if (isset($xmlarr['@']['NOTNULL'])) {
-            $notnull = strtolower(trim($xmlarr['@']['NOTNULL']));
-            if ($notnull == 'true') {
-                $this->notnull = true;
-            } else if ($notnull == 'false') {
-                $this->notnull = false;
-            } else {
-                $this->errormsg = 'Incorrect NOTNULL attribute (true/false allowed)';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        }
-
-        if (isset($xmlarr['@']['SEQUENCE'])) {
-            $sequence = strtolower(trim($xmlarr['@']['SEQUENCE']));
-            if ($sequence == 'true') {
-                $this->sequence = true;
-            } else if ($sequence == 'false') {
-                $this->sequence = false;
-            } else {
-                $this->errormsg = 'Incorrect SEQUENCE attribute (true/false allowed)';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        }
-
-        if (isset($xmlarr['@']['DEFAULT'])) {
-            $this->setDefault(trim($xmlarr['@']['DEFAULT']));
-        }
-
-        if (isset($xmlarr['@']['ENUM'])) {
-            $enum = strtolower(trim($xmlarr['@']['ENUM']));
-            if ($enum == 'true') {
-                $this->enum = true;
-            } else if ($enum == 'false') {
-                $this->enum = false;
-            } else {
-                $this->errormsg = 'Incorrect ENUM attribute (true/false allowed)';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        }
-
-        if (isset($xmlarr['@']['ENUMVALUES'])) {
-            $enumvalues = trim($xmlarr['@']['ENUMVALUES']);
-            if (!$this->enum) {
-                $this->errormsg = 'Wrong ENUMVALUES attribute (not ENUM)';
-                $this->debug($this->errormsg);
-                $result = false;
-                $this->enumvalues = $enumvalues;
-            } else {
-            /// Check we have a valid list (comma separated of quoted values)
-                $enumarr = explode(',',$enumvalues);
-                if ($enumarr) {
-                    foreach ($enumarr as $key => $enumelement) {
-                    /// Clear some spaces
-                        $enumarr[$key] = trim($enumelement);
-                        $enumelement = trim($enumelement);
-                    /// Skip if under error
-                        if (!$result) {
-                            continue;
-                        }
-                    /// Look for quoted strings
-                        if (substr($enumelement, 0, 1) != "'" ||
-                            substr($enumelement, -1, 1) != "'") {
-                            $this->errormsg = 'Incorrect ENUMVALUES attribute (some value is not properly quoted)';
-                            $this->debug($this->errormsg);
-                            $result = false;
-                        }
-                    }
-                } else {
-                    $this->errormsg = 'Incorrect ENUMVALUES attribute (comma separated of quoted values)';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            }
-        } else if ($this->enum) {
-            $this->errormsg = 'Incorrect ENUMVALUES attribute (field is not declared as ENUM)';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-    /// Finally, set the value
-        if ($this->enum) {
-            $this->enumvalues = $enumarr;
-        }
-
-        $decimals = NULL;
-        if (isset($xmlarr['@']['DECIMALS'])) {
-            $decimals = trim($xmlarr['@']['DECIMALS']);
-        /// Check for integer values
-            if ($this->type == XMLDB_TYPE_NUMBER ||
-                $this->type == XMLDB_TYPE_FLOAT) {
-                if (!(is_numeric($decimals)&&(intval($decimals)==floatval($decimals)))) {
-                    $this->errormsg = 'Incorrect DECIMALS attribute for number field';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                } else if ($this->length <= $decimals){
-                    $this->errormsg = 'Incorrect DECIMALS attribute (bigget than length)';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            } else {
-                $this->errormsg = 'Incorrect DECIMALS attribute for non-number field';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        } else {
-            if ($this->type == XMLDB_TYPE_NUMBER) {
-                $decimals = 0;
-            }
-        }
-     // Finally, set the decimals
-        if ($this->type == XMLDB_TYPE_NUMBER ||
-            $this->type == XMLDB_TYPE_FLOAT) {
-            $this->decimals = $decimals;
-        }
-
-        if (isset($xmlarr['@']['COMMENT'])) {
-            $this->comment = trim($xmlarr['@']['COMMENT']);
-        }
-
-        if (isset($xmlarr['@']['PREVIOUS'])) {
-            $this->previous = trim($xmlarr['@']['PREVIOUS']);
-        }
-
-        if (isset($xmlarr['@']['NEXT'])) {
-            $this->next = trim($xmlarr['@']['NEXT']);
-        }
-
-    /// Set some attributes
-        if ($result) {
-            $this->loaded = true;
-        }
-        $this->calculateHash();
-        return $result;
-    }
-
-    /**
-     * This function returns the correct XMLDB_TYPE_XXX value for the
-     * string passed as argument
-     */
-    function getXMLDBFieldType($type) {
-
-        $result = XMLDB_TYPE_INCORRECT;
-
-        switch (strtolower($type)) {
-            case 'int':
-                $result = XMLDB_TYPE_INTEGER;
-                break;
-            case 'number':
-                $result = XMLDB_TYPE_NUMBER;
-                break;
-            case 'float':
-                $result = XMLDB_TYPE_FLOAT;
-                break;
-            case 'char':
-                $result = XMLDB_TYPE_CHAR;
-                break;
-            case 'text':
-                $result = XMLDB_TYPE_TEXT;
-                break;
-            case 'binary':
-                $result = XMLDB_TYPE_BINARY;
-                break;
-            case 'datetime':
-                $result = XMLDB_TYPE_DATETIME;
-                break;
-        }
-    /// Return the normalized XMLDB_TYPE
-        return $result;
-    }
-
-    /**
-     * This function returns the correct name value for the
-     * XMLDB_TYPE_XXX passed as argument
-     */
-    function getXMLDBTypeName($type) {
-
-        $result = "";
-
-        switch (strtolower($type)) {
-            case XMLDB_TYPE_INTEGER:
-                $result = 'int';
-                break;
-            case XMLDB_TYPE_NUMBER:
-                $result = 'number';
-                break;
-            case XMLDB_TYPE_FLOAT:
-                $result = 'float';
-                break;
-            case XMLDB_TYPE_CHAR:
-                $result = 'char';
-                break;
-            case XMLDB_TYPE_TEXT:
-                $result = 'text';
-                break;
-            case XMLDB_TYPE_BINARY:
-                $result = 'binary';
-                break;
-            case XMLDB_TYPE_DATETIME:
-                $result = 'datetime';
-                break;
-        }
-    /// Return the normalized name
-        return $result;
-    }
-
-    /**
-     * This function calculate and set the hash of one XMLDBField
-     */
-     function calculateHash($recursive = false) {
-        if (!$this->loaded) {
-            $this->hash = NULL;
-        } else {
-            $key = $this->name . $this->type . $this->length .
-                   $this->unsigned . $this->notnull . $this->sequence .
-                   $this->decimals . $this->comment;
-            if ($this->enum) {
-                $key .= implode(', ',$this->enumvalues);
-            }
-            $this->hash = md5($key);
-        }
-    }
-
-    /**
-     *This function will output the XML text for one field
-     */
-    function xmlOutput() {
-        $o = '';
-        $o.= '        <FIELD NAME="' . $this->name . '"';
-        $o.= ' TYPE="' . $this->getXMLDBTypeName($this->type) . '"';
-        if ($this->length) {
-            $o.= ' LENGTH="' . $this->length . '"';
-        }
-        if ($this->notnull) {
-            $notnull = 'true';
-        } else {
-            $notnull = 'false';
-        }
-        $o.= ' NOTNULL="' . $notnull . '"';
-        if ($this->unsigned) {
-            $unsigned = 'true';
-        } else {
-            $unsigned = 'false';
-        }
-        if ($this->type == XMLDB_TYPE_INTEGER ||
-            $this->type == XMLDB_TYPE_NUMBER ||
-            $this->type == XMLDB_TYPE_FLOAT) {
-            if ($this->unsigned) {
-                $unsigned = 'true';
-            } else {
-                $unsigned = 'false';
-            }
-            $o.= ' UNSIGNED="' . $unsigned . '"';
-        }
-        if (!$this->sequence && $this->default !== NULL) {
-            $o.= ' DEFAULT="' . $this->default . '"';
-        }
-        if ($this->sequence) {
-            $sequence = 'true';
-        } else {
-            $sequence = 'false';
-        }
-        $o.= ' SEQUENCE="' . $sequence . '"';
-        if ($this->enum) {
-            $enum = 'true';
-        } else {
-            $enum = 'false';
-        }
-        $o.= ' ENUM="' . $enum . '"';
-        if ($this->enum) {
-            $o.= ' ENUMVALUES="' . implode(', ', $this->enumvalues) . '"';
-        }
-        if ($this->decimals !== NULL) {
-            $o.= ' DECIMALS="' . $this->decimals . '"';
-        }
-        if ($this->comment) {
-            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
-        }
-        if ($this->previous) {
-            $o.= ' PREVIOUS="' . $this->previous . '"';
-        }
-        if ($this->next) {
-            $o.= ' NEXT="' . $this->next . '"';
-        }
-        $o.= '/>' . "\n";
-
-        return $o;
-    }
-
-    /**
-     * This function will set all the attributes of the XMLDBField object
-     * based on information passed in one ADOField
-     */
-    function setFromADOField($adofield) {
-
-    /// Calculate the XMLDB_TYPE
-        switch (strtolower($adofield->type)) {
-            case 'int':
-            case 'tinyint':
-            case 'smallint':
-            case 'bigint':
-            case 'integer':
-                $this->type = XMLDB_TYPE_INTEGER;
-                break;
-            case 'number':
-            case 'decimal':
-            case 'dec':
-            case 'numeric':
-                $this->type = XMLDB_TYPE_NUMBER;
-                break;
-            case 'float':
-            case 'double':
-                $this->type = XMLDB_TYPE_FLOAT;
-                break;
-            case 'char':
-            case 'varchar':
-            case 'enum':
-                $this->type = XMLDB_TYPE_CHAR;
-                break;
-            case 'text':
-            case 'tinytext':
-            case 'mediumtext':
-            case 'longtext':
-                $this->type = XMLDB_TYPE_TEXT;
-                break;
-            case 'blob':
-            case 'tinyblob':
-            case 'mediumblob':
-            case 'longblob':
-                $this->type = XMLDB_TYPE_BINARY;
-                break;
-            case 'datetime':
-            case 'timestamp':
-                $this->type = XMLDB_TYPE_DATETIME;
-                break;
-            default:
-                $this->type = XMLDB_TYPE_TEXT;
-        }
-    /// Calculate the length of the field
-        if ($adofield->max_length > 0 &&
-               ($this->type == XMLDB_TYPE_INTEGER ||
-                $this->type == XMLDB_TYPE_NUMBER  ||
-                $this->type == XMLDB_TYPE_FLOAT   ||
-                $this->type == XMLDB_TYPE_CHAR)) {
-            $this->length = $adofield->max_length;
-        }
-        if ($this->type == XMLDB_TYPE_TEXT) {
-            switch (strtolower($adofield->type)) {
-                case 'tinytext':
-                case 'text':
-                    $this->length = 'small';
-                    break;
-                case 'mediumtext':
-                    $this->length = 'medium';
-                    break;
-                case 'longtext':
-                    $this->length = 'big';
-                    break;
-                default:
-                    $this->length = 'small';
-            }
-        }
-        if ($this->type == XMLDB_TYPE_BINARY) {
-            switch (strtolower($adofield->type)) {
-                case 'tinyblob':
-                case 'blob':
-                    $this->length = 'small';
-                    break;
-                case 'mediumblob':
-                    $this->length = 'medium';
-                    break;
-                case 'longblob':
-                    $this->length = 'big';
-                    break;
-                default:
-                    $this->length = 'small';
-            }
-        }
-    /// Calculate the decimals of the field
-        if ($adofield->max_length > 0 &&
-            $adofield->scale &&
-               ($this->type == XMLDB_TYPE_NUMBER ||
-                $this->type == XMLDB_TYPE_FLOAT)) {
-            $this->decimals = $adofield->scale;
-        }
-    /// Calculate the unsigned field
-        if ($adofield->unsigned &&
-               ($this->type == XMLDB_TYPE_INTEGER ||
-                $this->type == XMLDB_TYPE_NUMBER  ||
-                $this->type == XMLDB_TYPE_FLOAT)) {
-            $this->unsigned = true;
-        }
-    /// Calculate the notnull field
-        if ($adofield->not_null) {
-            $this->notnull = true;
-        }
-    /// Calculate the default field
-        if ($adofield->has_default) {
-            $this->default = $adofield->default_value;
-        }
-    /// Calculate the sequence field
-        if ($adofield->auto_increment) {
-            $this->sequence = true;
-        /// Sequence fields are always unsigned
-            $this->unsigned = true;
-        }
-    /// Calculate the enum and enumvalues field
-        if ($adofield->type == 'enum') {
-            $this->enum = true;
-            $this->enumvalues = $adofield->enums;
-        }
-    /// Some more fields
-        $this->loaded = true;
-        $this->changed = true;
-    }
-
-    /**
-     * Returns the PHP code needed to define one XMLDBField
-     */
-    function getPHP($includeprevious=true) {
-
-        $result = '';
-
-    /// The XMLDBTYPE
-        switch ($this->getType()) {
-            case XMLDB_TYPE_INTEGER:
-                $result .= 'XMLDB_TYPE_INTEGER' . ', ';
-                break;
-            case XMLDB_TYPE_NUMBER:
-                $result .= 'XMLDB_TYPE_NUMBER' . ', ';
-                break;
-            case XMLDB_TYPE_FLOAT:
-                $result .= 'XMLDB_TYPE_FLOAT' . ', ';
-                break;
-            case XMLDB_TYPE_CHAR:
-                $result .= 'XMLDB_TYPE_CHAR' . ', ';
-                break;
-            case XMLDB_TYPE_TEXT:
-                $result .= 'XMLDB_TYPE_TEXT' . ', ';
-                break;
-            case XMLDB_TYPE_BINARY:
-                $result .= 'XMLDB_TYPE_BINARY' . ', ';
-                break;
-            case XMLDB_TYPE_DATETIME:
-                $result .= 'XMLDB_TYPE_DATETIME' . ', ';
-                break;
-            case XMLDB_TYPE_TIMESTAMP:
-                $result .= 'XMLDB_TYPE_TIMESTAMP' . ', ';
-                break;
-        }
-    /// The length
-        $length = $this->getLength();
-        $decimals = $this->getDecimals();
-        if (!empty($length)) {
-            $result .= "'" . $length;
-            if (!empty($decimals)) {
-                $result .= ', ' . $decimals;
-            }
-            $result .= "', ";
-        } else {
-            $result .= 'null, ';
-        }
-    /// Unsigned (only applicable to numbers)
-        $unsigned = $this->getUnsigned();
-        if (!empty($unsigned) &&
-           ($this->getType() == XMLDB_TYPE_INTEGER || $this->getType() == XMLDB_TYPE_NUMBER || $this->getType() == XMLDB_TYPE_FLOAT)) {
-            $result .= 'XMLDB_UNSIGNED' . ', ';
-        } else {
-            $result .= 'null, ';
-        }
-    /// Not Null
-        $notnull = $this->getNotnull();
-        if (!empty($notnull)) {
-            $result .= 'XMLDB_NOTNULL' . ', ';
-        } else {
-            $result .= 'null, ';
-        }
-    /// Sequence
-        $sequence = $this->getSequence();
-        if (!empty($sequence)) {
-            $result .= 'XMLDB_SEQUENCE' . ', ';
-        } else {
-            $result .= 'null, ';
-        }
-    /// Enum
-        $enum = $this->getEnum();
-        if (!empty($enum)) {
-            $result .= 'XMLDB_ENUM' . ', ';
-        } else {
-            $result .= 'null, ';
-        }
-    /// Enumvalues
-        $enumvalues = $this->getEnumValues();
-        if (!empty($enumvalues)) {
-            $result .= 'array(' . implode(', ', $enumvalues) . '), ';
-        } else {
-            $result .= 'null, ';
-        }
-    /// Default
-        $default =  $this->getDefault();
-        if ($default !== null && !$this->getSequence()) {
-            $result .= "'" . $default . "'";
-        } else {
-            $result .= 'null';
-        }
-    /// Previous (decided by parameter)
-        if ($includeprevious) {
-            $previous = $this->getPrevious();
-            if (!empty($previous)) {
-                $result .= ", '" . $previous . "'";
-            } else {
-                $result .= ', null';
-            }
-        }
-    /// Return result
-        return $result;
-    }
-
-    /**
-     * Shows info in a readable format
-     */
-    function readableInfo() {
-        $o = '';
-    /// type
-        $o .= $this->getXMLDBTypeName($this->type);
-    /// length
-        if ($this->type == XMLDB_TYPE_INTEGER ||
-            $this->type == XMLDB_TYPE_NUMBER  ||
-            $this->type == XMLDB_TYPE_FLOAT   ||
-            $this->type == XMLDB_TYPE_CHAR) {
-            if ($this->length) {
-                $o .= ' (' . $this->length;
-                if ($this->type == XMLDB_TYPE_NUMBER  ||
-                    $this->type == XMLDB_TYPE_FLOAT) {
-                    if ($this->decimals !== NULL) {
-                        $o .= ', ' . $this->decimals;
-                    }
-                }
-                $o .= ')';
-            }
-        }
-        if ($this->type == XMLDB_TYPE_TEXT ||
-            $this->type == XMLDB_TYPE_BINARY) {
-                $o .= ' (' . $this->length . ')';
-        }
-    /// enum
-        if ($this->enum) {
-            $o .= ' enum(' . implode(', ', $this->enumvalues) . ')';
-        }
-    /// unsigned
-        if ($this->type == XMLDB_TYPE_INTEGER ||
-            $this->type == XMLDB_TYPE_NUMBER ||
-            $this->type == XMLDB_TYPE_FLOAT) {
-            if ($this->unsigned) {
-                $o .= ' unsigned';
-            } else {
-                $o .= ' signed';
-            }
-        }
-    /// not null
-        if ($this->notnull) {
-            $o .= ' not null';
-        }
-    /// default
-        if ($this->default !== NULL) {
-            $o .= ' default ';
-            if ($this->type == XMLDB_TYPE_CHAR ||
-                $this->type == XMLDB_TYPE_TEXT) {
-                    $o .= "'" . $this->default . "'";
-            } else {
-                $o .= $this->default;
-            }
-        }
-    /// sequence
-        if ($this->sequence) {
-            $o .= ' auto-numbered';
-        }
-
-        return $o;
-    }
-}
-
-?>
Index: lib/xmldb/classes/XMLDBConstants.php
===================================================================
RCS file: lib/xmldb/classes/XMLDBConstants.php
diff -N lib/xmldb/classes/XMLDBConstants.php
--- lib/xmldb/classes/XMLDBConstants.php	10 Oct 2007 05:25:14 -0000	1.5
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,74 +0,0 @@
-<?php // $Id: XMLDBConstants.php,v 1.5 2007/10/10 05:25:14 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This file contains all the constants and variables used
-/// by the XMLDB interface
-
-/// First, some constants to be used by actions
-    define('ACTION_NONE',             0);  //Default flags for class
-    define('ACTION_GENERATE_HTML',    1);  //The invoke function will return HTML
-    define('ACTION_GENERATE_XML',     2);  //The invoke function will return HTML
-    define('ACTION_HAVE_SUBACTIONS',  1);  //The class can have subaction
-
-/// Now the allowed DB Field Types
-    define ('XMLDB_TYPE_INCORRECT',   0);  //Wrong DB Type
-    define ('XMLDB_TYPE_INTEGER',     1);  //Integer
-    define ('XMLDB_TYPE_NUMBER',      2);  //Decimal number
-    define ('XMLDB_TYPE_FLOAT',       3);  //Floating Point number
-    define ('XMLDB_TYPE_CHAR',        4);  //String
-    define ('XMLDB_TYPE_TEXT',        5);  //Text
-    define ('XMLDB_TYPE_BINARY',      6);  //Binary
-    define ('XMLDB_TYPE_DATETIME',    7);  //Datetime
-    define ('XMLDB_TYPE_TIMESTAMP',   8);  //Timestamp
-
-/// Now the allowed DB Keys
-    define ('XMLDB_KEY_INCORRECT',     0);  //Wrong DB Key
-    define ('XMLDB_KEY_PRIMARY',       1);  //Primary Keys
-    define ('XMLDB_KEY_UNIQUE',        2);  //Unique Keys
-    define ('XMLDB_KEY_FOREIGN',       3);  //Foreign Keys
-    define ('XMLDB_KEY_CHECK',         4);  //Check Constraints - NOT USED!
-    define ('XMLDB_KEY_FOREIGN_UNIQUE',5);  //Foreign Key + Unique Key
-
-/// Now the allowed Statement Types
-    define ('XMLDB_STATEMENT_INCORRECT',   0);  //Wrong Statement Type
-    define ('XMLDB_STATEMENT_INSERT',      1);  //Insert Statements
-    define ('XMLDB_STATEMENT_UPDATE',      2);  //Update Statements
-    define ('XMLDB_STATEMENT_DELETE',      3);  //Delete Statements
-    define ('XMLDB_STATEMENT_CUSTOM',      4);  //Custom Statements
-
-/// Some other useful Constants
-    define ('XMLDB_UNSIGNED',        true);  //If the field is going to be unsigned
-    define ('XMLDB_NOTNULL',         true);  //If the field is going to be not null
-    define ('XMLDB_SEQUENCE',        true);  //If the field is going to be a sequence
-    define ('XMLDB_ENUM',            true);  //If the field is going to be a enumeration of possible fields
-    define ('XMLDB_INDEX_UNIQUE',    true);  //If the index is going to be unique
-    define ('XMLDB_INDEX_NOTUNIQUE',false);  //If the index is NOT going to be unique
-
-/// Some strings used widely
-    define ('XMLDB_LINEFEED', "\n");
-    define ('XMLDB_PHP_HEADER', '    if ($result && $oldversion < XXXXXXXXXX) {' . XMLDB_LINEFEED);
-    define ('XMLDB_PHP_FOOTER', '    }' . XMLDB_LINEFEED);
-?>
Index: lib/xmldb/classes/XMLDBIndex.class.php
===================================================================
RCS file: lib/xmldb/classes/XMLDBIndex.class.php
diff -N lib/xmldb/classes/XMLDBIndex.class.php
--- lib/xmldb/classes/XMLDBIndex.class.php	10 Oct 2007 05:25:14 -0000	1.9
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,264 +0,0 @@
-<?php // $Id: XMLDBIndex.class.php,v 1.9 2007/10/10 05:25:14 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class represent one XMLDB Index
-
-class XMLDBIndex extends XMLDBObject {
-
-    var $unique;
-    var $fields;
-
-    /**
-     * Creates one new XMLDBIndex
-     */
-    function XMLDBIndex($name) {
-        parent::XMLDBObject($name);
-        $this->unique = false;
-        $this->fields = array();
-    }
-
-    /**
-     * Set all the attributes of one XMLDBIndex
-     *
-     * @param string type XMLDB_INDEX_UNIQUE, XMLDB_INDEX_NOTUNIQUE
-     * @param array fields an array of fieldnames to build the index over
-     */
-    function setAttributes($type, $fields) {
-        $this->unique = !empty($type) ? true : false;
-        $this->fields = $fields;
-    }
-
-    /**
-     * Get the index unique
-     */
-    function getUnique() {
-        return $this->unique;
-    }
-
-    /**
-     * Set the index unique
-     */
-    function setUnique($unique = true) {
-        $this->unique = $unique;
-    }
-
-    /**
-     * Set the index fields
-     */
-    function setFields($fields) {
-        $this->fields = $fields;
-    }
-
-    /**
-     * Get the index fields
-     */
-    function &getFields() {
-        return $this->fields;
-    }
-
-    /**
-     * Load data from XML to the index
-     */
-    function arr2XMLDBIndex($xmlarr) {
-
-        $result = true;
-
-    /// Debug the table
-    /// traverse_xmlize($xmlarr);                   //Debug
-    /// print_object ($GLOBALS['traverse_array']);  //Debug
-    /// $GLOBALS['traverse_array']="";              //Debug
-
-    /// Process key attributes (name, unique, fields, comment, previous, next)
-        if (isset($xmlarr['@']['NAME'])) {
-            $this->name = trim($xmlarr['@']['NAME']);
-        } else {
-            $this->errormsg = 'Missing NAME attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-        if (isset($xmlarr['@']['UNIQUE'])) {
-            $unique = strtolower(trim($xmlarr['@']['UNIQUE']));
-            if ($unique == 'true') {
-                $this->unique = true;
-            } else if ($unique == 'false') {
-                $this->unique = false;
-            } else {
-                $this->errormsg = 'Incorrect UNIQUE attribute (true/false allowed)';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        } else {
-                $this->errormsg = 'Undefined UNIQUE attribute';
-                $this->debug($this->errormsg);
-                $result = false;
-        }
-
-        if (isset($xmlarr['@']['FIELDS'])) {
-            $fields = strtolower(trim($xmlarr['@']['FIELDS']));
-            if ($fields) {
-                $fieldsarr = explode(',',$fields);
-                if ($fieldsarr) {
-                    foreach ($fieldsarr as $key => $element) {
-                        $fieldsarr [$key] = trim($element);
-                    }
-                } else {
-                    $this->errormsg = 'Incorrect FIELDS attribute (comma separated of fields)';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            } else {
-                $this->errormsg = 'Empty FIELDS attribute';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        } else {
-            $this->errormsg = 'Missing FIELDS attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-    /// Finally, set the array of fields
-        $this->fields = $fieldsarr;
-
-        if (isset($xmlarr['@']['COMMENT'])) {
-            $this->comment = trim($xmlarr['@']['COMMENT']);
-        }
-
-        if (isset($xmlarr['@']['PREVIOUS'])) {
-            $this->previous = trim($xmlarr['@']['PREVIOUS']);
-        }
-
-        if (isset($xmlarr['@']['NEXT'])) {
-            $this->next = trim($xmlarr['@']['NEXT']);
-        }
-
-    /// Set some attributes
-        if ($result) {
-            $this->loaded = true;
-        }
-        $this->calculateHash();
-        return $result;
-    }
-
-    /**
-     * This function calculate and set the hash of one XMLDBIndex
-     */
-     function calculateHash($recursive = false) {
-        if (!$this->loaded) {
-            $this->hash = NULL;
-        } else {
-            $key = $this->unique . implode (', ', $this->fields);
-            $this->hash = md5($key);
-        }
-    }
-
-    /**
-     *This function will output the XML text for one index
-     */
-    function xmlOutput() {
-        $o = '';
-        $o.= '        <INDEX NAME="' . $this->name . '"';
-        if ($this->unique) {
-            $unique = 'true';
-        } else {
-            $unique = 'false';
-        }
-        $o.= ' UNIQUE="' . $unique . '"';
-        $o.= ' FIELDS="' . implode(', ', $this->fields) . '"';
-        if ($this->comment) {
-            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
-        }
-        if ($this->previous) {
-            $o.= ' PREVIOUS="' . $this->previous . '"';
-        }
-        if ($this->next) {
-            $o.= ' NEXT="' . $this->next . '"';
-        }
-        $o.= '/>' . "\n";
-
-        return $o;
-    }
-
-    /**
-     * This function will set all the attributes of the XMLDBIndex object
-     * based on information passed in one ADOindex
-     */
-    function setFromADOIndex($adoindex) {
-
-    /// Set the unique field
-        $this->unique = false;
-    /// Set the fields, converting all them to lowercase
-        $fields = array_flip(array_change_key_case(array_flip($adoindex['columns'])));
-        $this->fields = $fields;
-    /// Some more fields
-        $this->loaded = true;
-        $this->changed = true;
-    }
-
-    /**
-     * Returns the PHP code needed to define one XMLDBIndex
-     */
-    function getPHP() {
-
-        $result = '';
-
-    /// The type
-        $unique = $this->getUnique();
-        if (!empty($unique)) {
-            $result .= 'XMLDB_INDEX_UNIQUE, ';
-        } else {
-            $result .= 'XMLDB_INDEX_NOTUNIQUE, ';
-        }
-    /// The fields
-        $indexfields = $this->getFields();
-        if (!empty($indexfields)) {
-            $result .= 'array(' . "'".  implode("', '", $indexfields) . "')";
-        } else {
-            $result .= 'null';
-        }
-    /// Return result
-        return $result;
-    }
-
-    /**
-     * Shows info in a readable format
-     */
-    function readableInfo() {
-        $o = '';
-    /// unique
-        if ($this->unique) {
-            $o .= 'unique';
-        } else {
-            $o .= 'not unique';
-        }
-    /// fields
-        $o .= ' (' . implode(', ', $this->fields) . ')';
-
-        return $o;
-    }
-}
-
-?>
Index: lib/xmldb/classes/XMLDBFile.class.php
===================================================================
RCS file: lib/xmldb/classes/XMLDBFile.class.php
diff -N lib/xmldb/classes/XMLDBFile.class.php
--- lib/xmldb/classes/XMLDBFile.class.php	10 Oct 2007 05:25:14 -0000	1.6
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,201 +0,0 @@
-<?php // $Id: XMLDBFile.class.php,v 1.6 2007/10/10 05:25:14 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class represents an entire XMLDB file
-
-class XMLDBFile extends XMLDBObject {
-
-    var $path;
-    var $schema;
-    var $dtd;
-    var $xmldb_structure;
-
-    /**
-     * Constructor of the XMLDBFile
-     */
-    function XMLDBFile ($path) {
-        parent::XMLDBObject($path);
-        $this->path = $path;
-        $this->xmldb_structure = NULL;
-    }
-
-    /**
-     * Determine if the XML file exists
-     */
-    function fileExists() {
-        if (file_exists($this->path) && is_readable($this->path)) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Determine if the XML is writeable
-     */
-    function fileWriteable() {
-        if (is_writeable(dirname($this->path))) {
-            return true;
-        }
-        return false;
-    }
-
-    function &getStructure() {
-        return $this->xmldb_structure;
-    }
-
-    /**
-     * This function will check/validate the XML file for correctness 
-     * Dinamically if will use the best available checker/validator
-     * (expat syntax checker or DOM schema validator
-     */
-    function validateXMLStructure() {
-
-    /// Going to perform complete DOM schema validation
-        if (extension_loaded('dom')) {
-        /// Let's capture errors
-        if (function_exists('libxml_use_internal_errors')) {
-            libxml_use_internal_errors(true); // This function is PHP5 only (MDL-8730)
-        }
-
-        /// Create and load XML file
-            $parser = new DOMDocument();
-            $parser->load($this->path);
-        /// Only validate if we have a schema
-            if (!empty($this->schema) && file_exists($this->schema)) {
-                $parser->schemaValidate($this->schema);
-            }
-        /// Check for errors
-            $errors = false;
-            if (function_exists('libxml_get_errors')) {
-                $errors = libxml_get_errors();
-            }
-
-        /// Prepare errors
-            if (!empty($errors)) {
-            /// Create one structure to store errors
-                $structure = new XMLDBStructure($this->path);
-            /// Add errors to structure
-                $structure->errormsg = 'XML Error: ';
-                foreach ($errors as $error) {
-                    $structure->errormsg .= sprintf("%s at line %d. ", 
-                                                     trim($error->message, "\n\r\t ."),
-                                                     $error->line);
-                }
-            /// Add structure to file
-                $this->xmldb_structure = $structure;
-            /// Check has failed
-                return false;
-            }
-        }
-    /// Going to perform expat simple check (no validation)
-        else if (function_exists('xml_parser_create')) {
-            $parser = xml_parser_create();
-            if (!xml_parse($parser, file_get_contents($this->path))) {
-            /// Create one structure to store errors
-                $structure = new XMLDBStructure($this->path);
-            /// Add error to structure
-                $structure->errormsg = sprintf("XML Error: %s at line %d", 
-                         xml_error_string(xml_get_error_code($parser)),
-                         xml_get_current_line_number($parser));
-            /// Add structure to file
-                $this->xmldb_structure = $structure;
-            /// Check has failed
-                return false;
-            }
-        /// Free parser resources
-            xml_parser_free($parser);
-        }
-    /// Arriving here, something is really wrong because nor dom not expat are present
-        else {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Load and the XMLDB structure from file
-     */
-    function loadXMLStructure() {
-        if ($this->fileExists()) {
-        /// Let's validate the XML file
-            if (!$this->validateXMLStructure()) {
-                return false;
-            }
-        /// File exists, so let's process it
-        /// Load everything to a big array
-            $xmlarr = xmlize(file_get_contents($this->path));
-        /// Convert array to xmldb structure
-            $this->xmldb_structure = $this->arr2XMLDBStructure($xmlarr);
-        /// Analize results
-            if ($this->xmldb_structure->isLoaded()) {
-                $this->loaded = true;
-                return true;
-            } else {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * This function takes an xmlized array and put it into one XMLDBStructure
-     */
-    function arr2XMLDBStructure ($xmlarr) {
-        $structure = new XMLDBStructure($this->path);
-        $structure->arr2XMLDBStructure($xmlarr);
-        return $structure;
-    }
-
-    /**
-     * This function sets the DTD of the XML file
-     */
-    function setDTD($path) {
-        $this->dtd = $path;
-    }
-
-    /**
-     * This function sets the schema of the XML file
-     */
-    function setSchema($path) {
-        $this->schema = $path;
-    }
-
-    /**
-     * This function saves the whole XMLDBStructure to its file
-     */
-    function saveXMLFile() {
-
-        $result = true;
-
-        $structure =& $this->getStructure();
-
-        $result = file_put_contents($this->path, $structure->xmlOutput());
-
-        return $result;
-    }
-}
-
-?>
Index: lib/xmldb/classes/XMLDBStatement.class.php
===================================================================
RCS file: lib/xmldb/classes/XMLDBStatement.class.php
diff -N lib/xmldb/classes/XMLDBStatement.class.php
--- lib/xmldb/classes/XMLDBStatement.class.php	10 Oct 2007 05:25:14 -0000	1.7
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,423 +0,0 @@
-<?php // $Id: XMLDBStatement.class.php,v 1.7 2007/10/10 05:25:14 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class represent one XMLDB Statement
-/// (a group of SQL arbitrary sentences)
-/// (only INSERT is allowed for now)
-
-class XMLDBStatement extends XMLDBObject {
-
-    var $table;     // Table we are handling
-    var $type;      // XMLDB_STATEMENT_TYPE
-    var $sentences; // Collection of sentences in the statement
-
-    /**
-     * Creates one new XMLDBStatement
-     */
-    function XMLDBStatement($name) {
-        parent::XMLDBObject($name);
-        $this->table     = NULL;
-        $this->type      = XMLDB_STATEMENT_INCORRECT;
-        $this->sentences = array();
-    }
-
-    /**
-     * Get the statement table
-     */
-    function getTable() {
-        return $this->table;
-    }
-
-    /**
-     * Get the statement type
-     */
-    function getType() {
-        return $this->type;
-    }
-
-    /**
-     * Get the statement sentences
-     */
-    function &getSentences() {
-        return $this->sentences;
-    }
-
-    /**
-     * Set the statement table
-     */
-    function setTable($table) {
-        $this->table = $table;
-    }
-
-    /**
-     * Set the statement type
-     */
-    function setType($type) {
-        $this->type = $type;
-    }
-
-    /**
-     * Add one statement sentence
-     */
-    function addSentence($sentence) {
-        $this->sentences[] = $sentence;
-    }
-
-    /**
-     * Load data from XML to the index
-     */
-    function arr2XMLDBStatement($xmlarr) {
-
-        $result = true;
-
-    /// Debug the table
-    /// traverse_xmlize($xmlarr);                   //Debug
-    /// print_object ($GLOBALS['traverse_array']);  //Debug
-    /// $GLOBALS['traverse_array']="";              //Debug
-
-    /// Process key attributes (table, type, comment, previous, next)
-        if (isset($xmlarr['@']['TABLE'])) {
-            $this->table = strtolower(trim($xmlarr['@']['TABLE']));
-        } else {
-            $this->errormsg = 'Missing TABLE attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-        if (isset($xmlarr['@']['TYPE'])) {
-        /// Check for valid type
-            $type = $this->getXMLDBStatementType(trim($xmlarr['@']['TYPE']));
-            if ($type) {
-                $this->type = $type;
-            } else {
-                $this->errormsg = 'Invalid TYPE attribute';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        } else {
-            $this->errormsg = 'Missing TYPE attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-    /// Look for sentences
-        $sentencesarr = array();
-
-        if (isset($xmlarr['#']['SENTENCES'])) {
-            $sentences = $xmlarr['#']['SENTENCES'][0]['#']['SENTENCE'];
-            if ($sentences) {
-                foreach ($sentences as $sentence) {
-                    if (isset($sentence['@']['TEXT'])) {
-                        $sentencesarr[] = trim($sentence['@']['TEXT']);
-                    } else {
-                        $this->errormsg = 'Missing TEXT attribute in sentence';
-                        $this->debug($this->errormsg);
-                        $result = false;
-                    }
-                }
-            }
-        }
-
-    /// Finally, set the array of sentences
-        $this->sentences = $sentencesarr;
-
-    /// Now, perform some validations over sentences
-    /// XMLDB_STATEMENT_INSERT checks
-        if ($this->type == XMLDB_STATEMENT_INSERT) {
-        /// Separate fields and values into two arrays
-            if ($this->sentences) {
-                foreach ($this->sentences as $sentence) {
-                    $fields = $this->getFieldsFromInsertSentence($sentence);
-                    $values = $this->getValuesFromInsertSentence($sentence);
-                /// Check that we aren't inserting the id field
-                    if (in_array('id', $fields)) {
-                        $this->errormsg = 'Cannot insert the "id" field. It is an autonumeric column';
-                        $this->debug($this->errormsg);
-                        $result = false;
-                    }
-                    if ($result && count($fields) == 0) {
-                        $this->errormsg = 'Missing fields in sentence "' . $sentence . '"';
-                        $this->debug($this->errormsg);
-                        $result = false;
-                    }
-                    if ($result && count($values) == 0) {
-                        $this->errormsg = 'Missing values in sentence "' . $sentence . '"';
-                        $this->debug($this->errormsg);
-                        $result = false;
-                    }
-                    if ($result && count($fields) != count($values)) {
-                        $this->errormsg = 'Incorrect number of fields (' .implode(', ', $fields) . ') or values (' . implode(', ', $values) . ')';
-                        $this->debug($this->errormsg);
-                        $result = false;
-                    }
-                }
-            }
-        } else {
-        /// Sentences different from INSERT are not valid for now
-            $this->errormsg = 'Only INSERT statements are supported';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-        if (isset($xmlarr['@']['COMMENT'])) {
-            $this->comment = trim($xmlarr['@']['COMMENT']);
-        }
-
-        if (isset($xmlarr['@']['PREVIOUS'])) {
-            $this->previous = trim($xmlarr['@']['PREVIOUS']);
-        }
-
-        if (isset($xmlarr['@']['NEXT'])) {
-            $this->next = trim($xmlarr['@']['NEXT']);
-        }
-
-    /// Set some attributes
-        if ($result) {
-            $this->loaded = true;
-        }
-        $this->calculateHash();
-        return $result;
-    }
-
-    /**
-     * This function returns the correct XMLDB_STATEMENT_XXX value for the
-     * string passed as argument
-     */
-    function getXMLDBStatementType($type) {
-
-        $result = XMLDB_STATEMENT_INCORRECT;
-
-        switch (strtolower($type)) {
-            case 'insert':
-                $result = XMLDB_STATEMENT_INSERT;
-                break;
-            case 'update':
-                $result = XMLDB_STATEMENT_UPDATE;
-                break;
-            case 'delete':
-                $result = XMLDB_STATEMENT_DELETE;
-                break;
-            case 'custom':
-                $result = XMLDB_STATEMENT_CUSTOM;
-                break;
-        }
-    /// Return the normalized XMLDB_STATEMENT
-        return $result;
-    }
-
-    /**
-     * This function returns the correct name value for the
-     * XMLDB_STATEMENT_XXX passed as argument
-     */
-    function getXMLDBStatementName($type) {
-
-        $result = '';
-
-        switch (strtolower($type)) {
-            case XMLDB_STATEMENT_INSERT:
-                $result = 'insert';
-                break;
-            case XMLDB_STATEMENT_UPDATE:
-                $result = 'update';
-                break;
-            case XMLDB_STATEMENT_DELETE:
-                $result = 'delete';
-                break;
-            case XMLDB_STATEMENT_CUSTOM:
-                $result = 'custom';
-                break;
-        }
-    /// Return the normalized name
-        return $result;
-    }
-
-    /**
-     * This function calculate and set the hash of one XMLDBStatement
-     */
-     function calculateHash($recursive = false) {
-        if (!$this->loaded) {
-            $this->hash = NULL;
-        } else {
-            $key = $this->table . $this->type . implode (', ', $this->sentences);
-            $this->hash = md5($key);
-        }
-    }
-
-    /**
-     * This function will output the XML text for one statement
-     */
-    function xmlOutput() {
-        $o = '';
-        $o.= '    <STATEMENT NAME="' . $this->name . '" TYPE="' . XMLDBStatement::getXMLDBStatementName($this->type) . '" TABLE="' . $this->table . '"';
-        if ($this->comment) {
-            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
-        }
-        if ($this->previous) {
-            $o.= ' PREVIOUS="' . $this->previous . '"';
-        }
-        if ($this->next) {
-            $o.= ' NEXT="' . $this->next . '"';
-        }
-        if ($this->sentences) {
-            $o.= '>' . "\n";
-            $o.= '      <SENTENCES>' . "\n";
-            foreach ($this->sentences as $sentence) {
-                $o.= '        <SENTENCE TEXT="' . htmlspecialchars($sentence) . '" />' . "\n";
-            }
-            $o.= '      </SENTENCES>' . "\n";
-            $o.= '    </STATEMENT>' . "\n";
-        } else {
-            $o.= '/>' . "\n";
-        }
-
-        return $o;
-    }
-
-    /**
-     * This function will set all the attributes of the XMLDBIndex object
-     * based on information passed in one ADOindex
-     */
-    function setFromADOIndex($adoindex) {
-
-    /// Set the unique field
-        $this->unique = false;
-    /// Set the fields
-        $this->fields = $adoindex['columns'];
-    /// Some more fields
-        $this->loaded = true;
-        $this->changed = true;
-    }
-
-    /**
-     * Shows info in a readable format
-     */
-    function readableInfo() {
-        $o = '';
-    /// unique
-        if ($this->unique) {
-            $o .= 'unique';
-        } else {
-            $o .= 'not unique';
-        }
-    /// fields
-        $o .= ' (' . implode(', ', $this->fields) . ')';
-
-        return $o;
-    }
-
-    /**
-     * This function will return an array of fields from one INSERT sentence
-     */
-    function getFieldsFromInsertSentence($sentence) {
-
-        $fields = array();
-
-    /// Get first part from the sentence (before VALUES)
-        preg_match('/^\((.*)\)\s+VALUES/is', $sentence, $matches);
-        if (isset($matches[1])) {
-            $part = $matches[1];
-        /// Convert the comma separated string to an array
-            $arr = $this->comma2array($part);
-            if ($arr) {
-                $fields = $arr;
-            }
-        }
-
-        return $fields;
-    }
-
-    /**
-     * This function will return an array of values from one INSERT sentence
-     */
-    function getValuesFromInsertSentence($sentence) {
-
-        $values = array();
-
-    /// Get second part from the sentence (after VALUES)
-        preg_match('/VALUES\s*\((.*)\)$/is', $sentence, $matches);
-        if (isset($matches[1])) {
-            $part = $matches[1];
-        /// Convert the comma separated string to an array
-            $arr = $this->comma2array($part);
-            if ($arr) {
-                $values = $arr;
-            }
-        }
-
-        return $values;
-    }
-
-    /**
-     * This function will return the code needed to execute a collection
-     * of sentences present inside one statement for the specified BD
-     * and prefix.
-     * For now it only supports INSERT statements
-     */
-    function getExecuteStatementSQL ($dbtype, $prefix, $statement_end=true) {
-
-        $results = array();
-
-    /// Based on statement type
-        switch ($this->type) {
-            case XMLDB_STATEMENT_INSERT:
-                $results = $this->getExecuteInsertSQL($dbtype, $prefix, $statement_end);
-                break;
-            case XMLDB_STATEMENT_UPDATE:
-                break;
-            case XMLDB_STATEMENT_DELETE:
-                break;
-            case XMLDB_STATEMENT_CUSTOM:
-                break;
-        }
-
-        return $results;
-    }
-
-    /**
-     * This function will return the code needed to execute a collection
-     * of insert sentences present inside the statement for the specified BD
-     * and prefix. Just one simple wrapper over generators.
-     */
-    function getExecuteInsertSQL ($dbtype, $prefix, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-
-        $results = $generator->getExecuteInsertSQL($this);
-
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-
-        return $results;
-    }
-
-}
-
-?>
Index: lib/xmldb/classes/XMLDBKey.class.php
===================================================================
RCS file: lib/xmldb/classes/XMLDBKey.class.php
diff -N lib/xmldb/classes/XMLDBKey.class.php
--- lib/xmldb/classes/XMLDBKey.class.php	10 Oct 2007 05:25:14 -0000	1.8
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,457 +0,0 @@
-<?php // $Id: XMLDBKey.class.php,v 1.8 2007/10/10 05:25:14 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class represent one XMLDB Key
-
-class XMLDBKey extends XMLDBObject {
-
-    var $type;
-    var $fields;
-    var $reftable;
-    var $reffields;
-
-    /**
-     * Creates one new XMLDBKey
-     */
-    function XMLDBKey($name) {
-        parent::XMLDBObject($name);
-        $this->type = NULL;
-        $this->fields = array();
-        $this->reftable = NULL;
-        $this->reffields = array();
-    }
-
-    /**
-     * Set all the attributes of one XMLDBKey
-     *
-     * @param string type XMLDB_KEY_PRIMARY, XMLDB_KEY_UNIQUE, XMLDB_KEY_FOREIGN
-     * @param array fields an array of fieldnames to build the key over
-     * @param string reftable name of the table the FK points to or null
-     * @param array reffields an array of fieldnames in the FK table or null
-     */
-    function setAttributes($type, $fields, $reftable=null, $reffields=null) {
-        $this->type = $type;
-        $this->fields = $fields;
-        $this->reftable = $reftable;
-        $this->reffields = $reffields;
-    }
-
-    /**
-     * Get the key type
-     */
-    function getType() {
-        return $this->type;
-    }
-
-    /**
-     * Set the key type
-     */
-    function setType($type) {
-        $this->type = $type;
-    }
-
-    /**
-     * Set the key fields
-     */
-    function setFields($fields) {
-        $this->fields = $fields;
-    }
-
-    /**
-     * Set the key reftable
-     */
-    function setRefTable($reftable) {
-        $this->reftable = $reftable;
-    }
-
-    /**
-     * Set the key reffields
-     */
-    function setRefFields($reffields) {
-        $this->reffields = $reffields;
-    }
-
-    /**
-     * Get the key fields
-     */
-    function &getFields() {
-        return $this->fields;
-    }
-
-    /**
-     * Get the key reftable
-     */
-    function &getRefTable() {
-        return $this->reftable;
-    }
-
-    /**
-     * Get the key reffields
-     */
-    function &getRefFields() {
-        return $this->reffields;
-    }
-
-    /**
-     * Load data from XML to the key
-     */
-    function arr2XMLDBKey($xmlarr) {
-
-        $result = true;
-
-    /// Debug the table
-    /// traverse_xmlize($xmlarr);                   //Debug
-    /// print_object ($GLOBALS['traverse_array']);  //Debug
-    /// $GLOBALS['traverse_array']="";              //Debug
-
-    /// Process key attributes (name, type, fields, reftable,
-    /// reffields, comment, previous, next)
-        if (isset($xmlarr['@']['NAME'])) {
-            $this->name = trim($xmlarr['@']['NAME']);
-        } else {
-            $this->errormsg = 'Missing NAME attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-        if (isset($xmlarr['@']['TYPE'])) {
-        /// Check for valid type
-            $type = $this->getXMLDBKeyType(trim($xmlarr['@']['TYPE']));
-            if ($type) {
-                $this->type = $type;
-            } else {
-                $this->errormsg = 'Invalid TYPE attribute';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        } else {
-            $this->errormsg = 'Missing TYPE attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-        if (isset($xmlarr['@']['FIELDS'])) {
-            $fields = strtolower(trim($xmlarr['@']['FIELDS']));
-            if ($fields) {
-                $fieldsarr = explode(',',$fields);
-                if ($fieldsarr) {
-                    foreach ($fieldsarr as $key => $element) {
-                        $fieldsarr [$key] = trim($element);
-                    }
-                } else {
-                    $this->errormsg = 'Incorrect FIELDS attribute (comma separated of fields)';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            } else {
-                $this->errormsg = 'Empty FIELDS attribute';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        } else {
-            $this->errormsg = 'Missing FIELDS attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-    /// Finally, set the array of fields
-        $this->fields = $fieldsarr;
-
-        if (isset($xmlarr['@']['REFTABLE'])) {
-        /// Check we are in a FK
-            if ($this->type == XMLDB_KEY_FOREIGN ||
-                $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
-                $reftable = strtolower(trim($xmlarr['@']['REFTABLE']));
-                if (!$reftable) {
-                    $this->errormsg = 'Empty REFTABLE attribute';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            } else {
-                $this->errormsg = 'Wrong REFTABLE attribute (only FK can have it)';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        } else if ($this->type == XMLDB_KEY_FOREIGN ||
-                   $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
-            $this->errormsg = 'Missing REFTABLE attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-    /// Finally, set the reftable
-        if ($this->type == XMLDB_KEY_FOREIGN ||
-            $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
-            $this->reftable = $reftable;
-        }
-
-        if (isset($xmlarr['@']['REFFIELDS'])) {
-        /// Check we are in a FK
-            if ($this->type == XMLDB_KEY_FOREIGN ||
-                $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
-                $reffields = strtolower(trim($xmlarr['@']['REFFIELDS']));
-                if ($reffields) {
-                    $reffieldsarr = explode(',',$reffields);
-                    if ($reffieldsarr) {
-                        foreach ($reffieldsarr as $key => $element) {
-                            $reffieldsarr [$key] = trim($element);
-                        }
-                    } else {
-                        $this->errormsg = 'Incorrect REFFIELDS attribute (comma separated of fields)';
-                        $this->debug($this->errormsg);
-                        $result = false;
-                    }
-                } else {
-                    $this->errormsg = 'Empty REFFIELDS attribute';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            } else {
-                $this->errormsg = 'Wrong REFFIELDS attribute (only FK can have it)';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        } else if ($this->type == XMLDB_KEY_FOREIGN ||
-                   $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
-            $this->errormsg = 'Missing REFFIELDS attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-    /// Finally, set the array of reffields
-        if ($this->type == XMLDB_KEY_FOREIGN ||
-            $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
-            $this->reffields = $reffieldsarr;
-        }
-
-        if (isset($xmlarr['@']['COMMENT'])) {
-            $this->comment = trim($xmlarr['@']['COMMENT']);
-        }
-
-        if (isset($xmlarr['@']['PREVIOUS'])) {
-            $this->previous = trim($xmlarr['@']['PREVIOUS']);
-        }
-
-        if (isset($xmlarr['@']['NEXT'])) {
-            $this->next = trim($xmlarr['@']['NEXT']);
-        }
-
-    /// Set some attributes
-        if ($result) {
-            $this->loaded = true;
-        }
-        $this->calculateHash();
-        return $result;
-    }
-
-    /**
-     * This function returns the correct XMLDB_KEY_XXX value for the
-     * string passed as argument
-     */
-    function getXMLDBKeyType($type) {
-
-        $result = XMLDB_KEY_INCORRECT;
-
-        switch (strtolower($type)) {
-            case 'primary':
-                $result = XMLDB_KEY_PRIMARY;
-                break;
-            case 'unique':
-                $result = XMLDB_KEY_UNIQUE;
-                break;
-            case 'foreign':
-                $result = XMLDB_KEY_FOREIGN;
-                break;
-            case 'foreign-unique':
-                $result = XMLDB_KEY_FOREIGN_UNIQUE;
-                break;
-        /// case 'check':  //Not supported
-        ///     $result = XMLDB_KEY_CHECK;
-        ///     break;
-        }
-    /// Return the normalized XMLDB_KEY
-        return $result;
-    }
-
-    /**
-     * This function returns the correct name value for the
-     * XMLDB_KEY_XXX passed as argument
-     */
-    function getXMLDBKeyName($type) {
-
-        $result = '';
-
-        switch (strtolower($type)) {
-            case XMLDB_KEY_PRIMARY:
-                $result = 'primary';
-                break;
-            case XMLDB_KEY_UNIQUE:
-                $result = 'unique';
-                break;
-            case XMLDB_KEY_FOREIGN:
-                $result = 'foreign';
-                break;
-            case XMLDB_KEY_FOREIGN_UNIQUE:
-                $result = 'foreign-unique';
-                break;
-        /// case XMLDB_KEY_CHECK:  //Not supported
-        ///     $result = 'check';
-        ///     break;
-        }
-    /// Return the normalized name
-        return $result;
-    }
-
-    /**
-     * This function calculate and set the hash of one XMLDBKey
-     */
-     function calculateHash($recursive = false) {
-        if (!$this->loaded) {
-            $this->hash = NULL;
-        } else {
-            $key = $this->type . implode(', ', $this->fields);
-            if ($this->type == XMLDB_KEY_FOREIGN ||
-                $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
-                $key .= $this->reftable . implode(', ', $this->reffields);
-            }
-                    ;
-            $this->hash = md5($key);
-        }
-    }
-
-    /**
-     *This function will output the XML text for one key
-     */
-    function xmlOutput() {
-        $o = '';
-        $o.= '        <KEY NAME="' . $this->name . '"';
-        $o.= ' TYPE="' . $this->getXMLDBKeyName($this->type) . '"';
-        $o.= ' FIELDS="' . implode(', ', $this->fields) . '"';
-        if ($this->type == XMLDB_KEY_FOREIGN ||
-            $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
-            $o.= ' REFTABLE="' . $this->reftable . '"';
-            $o.= ' REFFIELDS="' . implode(', ', $this->reffields) . '"';
-        }
-        if ($this->comment) {
-            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
-        }
-        if ($this->previous) {
-            $o.= ' PREVIOUS="' . $this->previous . '"';
-        }
-        if ($this->next) {
-            $o.= ' NEXT="' . $this->next . '"';
-        }
-        $o.= '/>' . "\n";
-
-        return $o;
-    }
-
-    /**
-     * This function will set all the attributes of the XMLDBKey object
-     * based on information passed in one ADOkey
-     */
-    function setFromADOKey($adokey) {
-
-    /// Calculate the XMLDB_KEY
-        switch (strtolower($adokey['name'])) {
-            case 'primary':
-                $this->type = XMLDB_KEY_PRIMARY;
-                break;
-            default:
-                $this->type = XMLDB_KEY_UNIQUE;
-        }
-    /// Set the fields, converting all them to lowercase
-        $fields = array_flip(array_change_key_case(array_flip($adokey['columns'])));
-        $this->fields = $fields;
-    /// Some more fields
-        $this->loaded = true;
-        $this->changed = true;
-    }
-
-    /**
-     * Returns the PHP code needed to define one XMLDBKey
-     */
-    function getPHP() {
-
-        $result = '';
-
-    /// The type
-        switch ($this->getType()) {
-            case XMLDB_KEY_PRIMARY:
-                $result .= 'XMLDB_KEY_PRIMARY' . ', ';
-                break;
-            case XMLDB_KEY_UNIQUE:
-                $result .= 'XMLDB_KEY_UNIQUE' . ', ';
-                break;
-            case XMLDB_KEY_FOREIGN:
-                $result .= 'XMLDB_KEY_FOREIGN' . ', ';
-                break;
-        }
-    /// The fields
-        $keyfields = $this->getFields();
-        if (!empty($keyfields)) {
-            $result .= 'array(' . "'".  implode("', '", $keyfields) . "')";
-        } else {
-            $result .= 'null';
-        }
-    /// The FKs attributes
-        if ($this->getType() == XMLDB_KEY_FOREIGN) {
-        /// The reftable
-            $reftable = $this->getRefTable();
-            if (!empty($reftable)) {
-                $result .= ", '" . $reftable . "', ";
-            } else {
-                $result .= 'null, ';
-            }
-        /// The reffields
-            $reffields = $this->getRefFields();
-            if (!empty($reffields)) {
-                $result .= 'array(' . "'".  implode("', '", $reffields) . "')";
-            } else {
-                $result .= 'null';
-            }
-        }
-    /// Return result
-        return $result;
-    }
-
-    /**
-     * Shows info in a readable format
-     */
-    function readableInfo() {
-        $o = '';
-    /// type
-        $o .= $this->getXMLDBKeyName($this->type);
-    /// fields
-        $o .= ' (' . implode(', ', $this->fields) . ')';
-    /// foreign key
-        if ($this->type == XMLDB_KEY_FOREIGN ||
-            $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
-            $o .= ' references ' . $this->reftable . ' (' . implode(', ', $this->reffields) . ')';
-        }
-
-        return $o;
-    }
-}
-
-?>
Index: lib/xmldb/classes/XMLDBStructure.class.php
===================================================================
RCS file: lib/xmldb/classes/XMLDBStructure.class.php
diff -N lib/xmldb/classes/XMLDBStructure.class.php
--- lib/xmldb/classes/XMLDBStructure.class.php	10 Oct 2007 05:25:14 -0000	1.12
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,741 +0,0 @@
-<?php // $Id: XMLDBStructure.class.php,v 1.12 2007/10/10 05:25:14 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class represent one XMLDB structure
-
-class XMLDBStructure extends XMLDBObject {
-
-    var $path;
-    var $version;
-    var $tables;
-    var $statements;
-
-    /**
-     * Creates one new XMLDBStructure
-     */
-    function XMLDBStructure($name) {
-        parent::XMLDBObject($name);
-        $this->path = NULL;
-        $this->version = NULL;
-        $this->tables = array();
-        $this->statements = array();
-    }
-
-    /**
-     * Returns the path of the structure
-     */
-    function getPath() {
-        return $this->path;
-    }
-
-    /**
-     * Returns the version of the structure
-     */
-    function getVersion() {
-        return $this->version;
-    }
-
-    /**
-     * Returns one XMLDBTable
-     */
-    function &getTable($tablename) {
-        $i = $this->findTableInArray($tablename);
-        if ($i !== NULL) {
-            return $this->tables[$i];
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * Returns the position of one table in the array.
-     */
-    function &findTableInArray($tablename) {
-        foreach ($this->tables as $i => $table) {
-            if ($tablename == $table->getName()) {
-                return $i;
-            }
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * Returns the position of one statement in the array.
-     */
-    function &findStatementInArray($statementname) {
-        foreach ($this->statements as $i => $statement) {
-            if ($statementname == $statement->getName()) {
-                return $i;
-            }
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * This function will reorder the array of tables
-     */
-    function orderTables() {
-        $result = $this->orderElements($this->tables);
-        if ($result) {
-            $this->setTables($result);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * This function will reorder the array of statements
-     */
-    function orderStatements() {
-        $result = $this->orderElements($this->statements);
-        if ($result) {
-            $this->setStatements($result);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Returns the tables of the structure
-     */
-    function &getTables() {
-        return $this->tables;
-    }
-
-    /**
-     * Returns one XMLDBStatement
-     */
-    function &getStatement($statementname) {
-        $i = $this->findStatementInArray($statementname);
-        if ($i !== NULL) {
-            return $this->statements[$i];
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * Returns the statements of the structure
-     */
-    function &getStatements() {
-        return $this->statements;
-    }
-
-    /**
-     * Set the structure version
-     */
-    function setVersion($version) {
-        $this->version = $version;
-    }
-
-    /**
-     * Add one table to the structure, allowing to specify the desired order
-     * If it's not specified, then the table is added at the end.
-     */
-    function addTable(&$table, $after=NULL) {
-
-    /// Calculate the previous and next tables
-        $prevtable = NULL;
-        $nexttable = NULL;
-
-        if (!$after) {
-            $alltables =& $this->getTables();
-            if ($alltables) {
-                end($alltables);
-                $prevtable =& $alltables[key($alltables)];
-            }
-        } else {
-            $prevtable =& $this->getTable($after);
-        }
-        if ($prevtable && $prevtable->getNext()) {
-            $nexttable =& $this->getTable($prevtable->getNext());
-        }
-
-    /// Set current table previous and next attributes
-        if ($prevtable) {
-            $table->setPrevious($prevtable->getName());
-            $prevtable->setNext($table->getName());
-        }
-        if ($nexttable) {
-            $table->setNext($nexttable->getName());
-            $nexttable->setPrevious($table->getName());
-        }
-    /// Some more attributes
-        $table->setLoaded(true);
-        $table->setChanged(true);
-    /// Add the new table
-        $this->tables[] =& $table;
-    /// Reorder the whole structure
-        $this->orderTables($this->tables);
-    /// Recalculate the hash
-        $this->calculateHash(true);
-    /// We have one new table, so the structure has changed
-        $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
-        $this->setChanged(true);
-    }
-
-    /**
-     * Add one statement to the structure, allowing to specify the desired order
-     * If it's not specified, then the statement is added at the end.
-     */
-    function addStatement(&$statement, $after=NULL) {
-
-    /// Calculate the previous and next tables
-        $prevstatement = NULL;
-        $nextstatement = NULL;
-
-        if (!$after) {
-            $allstatements =& $this->getStatements();
-            if ($allstatements) {
-                end($allstatements);
-                $prevstatement =& $allstatements[key($allstatements)];
-            }
-        } else {
-            $prevstatement =& $this->getStatement($after);
-        }
-        if ($prevstatement && $prevstatement->getNext()) {
-            $nextstatement =& $this->getStatement($prevstatement->getNext());
-        }
-
-    /// Set current statement previous and next attributes
-        if ($prevstatement) {
-            $statement->setPrevious($prevstatement->getName());
-            $prevstatement->setNext($statement->getName());
-        }
-        if ($nextstatement) {
-            $statement->setNext($nextstatement->getName());
-            $nextstatement->setPrevious($statement->getName());
-        }
-    /// Some more attributes
-        $statement->setLoaded(true);
-        $statement->setChanged(true);
-    /// Add the new statement
-        $this->statements[] =& $statement;
-    /// Reorder the whole structure
-        $this->orderStatements($this->statements);
-    /// Recalculate the hash
-        $this->calculateHash(true);
-    /// We have one new statement, so the structure has changed
-        $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
-        $this->setChanged(true);
-    }
-
-    /**
-     * Delete one table from the Structure
-     */
-    function deleteTable($tablename) {
-
-        $table =& $this->getTable($tablename);
-        if ($table) {
-            $i = $this->findTableInArray($tablename);
-            $prevtable = NULL;
-            $nexttable = NULL;
-        /// Look for prev and next table
-            $prevtable =& $this->getTable($table->getPrevious());
-            $nexttable =& $this->getTable($table->getNext());
-        /// Change their previous and next attributes
-            if ($prevtable) {
-                $prevtable->setNext($table->getNext());
-            }
-            if ($nexttable) {
-                $nexttable->setPrevious($table->getPrevious());
-            }
-        /// Delete the table
-            unset($this->tables[$i]);
-        /// Reorder the tables
-            $this->orderTables($this->tables);
-        /// Recalculate the hash
-            $this->calculateHash(true);
-        /// We have one deleted table, so the structure has changed
-            $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
-            $this->setChanged(true);
-        }
-    }
-
-    /**
-     * Delete one statement from the Structure
-     */
-    function deleteStatement($statementname) {
-
-        $statement =& $this->getStatement($statementname);
-        if ($statement) {
-            $i = $this->findStatementInArray($statementname);
-            $prevstatement = NULL;
-            $nextstatement = NULL;
-        /// Look for prev and next statement
-            $prevstatement =& $this->getStatement($statement->getPrevious());
-            $nextstatement =& $this->getStatement($statement->getNext());
-        /// Change their previous and next attributes
-            if ($prevstatement) {
-                $prevstatement->setNext($statement->getNext());
-            }
-            if ($nextstatement) {
-                $nextstatement->setPrevious($statement->getPrevious());
-            }
-        /// Delete the statement
-            unset($this->statements[$i]);
-        /// Reorder the statements
-            $this->orderStatements($this->statements);
-        /// Recalculate the hash
-            $this->calculateHash(true);
-        /// We have one deleted statement, so the structure has changed
-            $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
-            $this->setChanged(true);
-        }
-    }
-
-    /**
-     * Set the tables
-     */
-    function setTables(&$tables) {
-        $this->tables = $tables;
-    }
-
-    /**
-     * Set the statements
-     */
-    function setStatements(&$statements) {
-        $this->statements = $statements;
-    }
-
-    /**
-     * Load data from XML to the structure
-     */
-    function arr2XMLDBStructure($xmlarr) {
-
-        global $CFG;
-
-        $result = true;
-
-    /// Debug the structure
-    /// traverse_xmlize($xmlarr);                   //Debug
-    /// print_object ($GLOBALS['traverse_array']);  //Debug
-    /// $GLOBALS['traverse_array']="";              //Debug
-
-    /// Process structure attributes (path, comment and version)
-        if (isset($xmlarr['XMLDB']['@']['PATH'])) {
-            $this->path = trim($xmlarr['XMLDB']['@']['PATH']);
-        } else {
-            $this->errormsg = 'Missing PATH attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-        if (isset($xmlarr['XMLDB']['@']['VERSION'])) {
-            $this->version = trim($xmlarr['XMLDB']['@']['VERSION']);
-        } else {
-            $this->errormsg = 'Missing VERSION attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-        if (isset($xmlarr['XMLDB']['@']['COMMENT'])) {
-            $this->comment = trim($xmlarr['XMLDB']['@']['COMMENT']);
-        } else if (!empty($CFG->xmldbdisablecommentchecking)) {
-            $this->comment = '';
-        } else {
-            $this->errormsg = 'Missing COMMENT attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-    /// Iterate over tables
-        if (isset($xmlarr['XMLDB']['#']['TABLES']['0']['#']['TABLE'])) {
-            foreach ($xmlarr['XMLDB']['#']['TABLES']['0']['#']['TABLE'] as $xmltable) {
-                if (!$result) { //Skip on error
-                    continue;
-                }
-                $name = trim($xmltable['@']['NAME']);
-                $table = new XMLDBTable($name);
-                $table->arr2XMLDBTable($xmltable);
-                $this->tables[] = $table;
-                if (!$table->isLoaded()) {
-                    $this->errormsg = 'Problem loading table ' . $name;
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            }
-        } else {
-            $this->errormsg = 'Missing TABLES section';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-    /// Perform some general checks over tables
-        if ($result && $this->tables) {
-        /// Check tables names are ok (lowercase, a-z _-)
-            if (!$this->checkNameValues($this->tables)) {
-                $this->errormsg = 'Some TABLES name values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Check previous & next are ok (duplicates and existing tables)
-            $this->fixPrevNext($this->tables);
-            if ($result && !$this->checkPreviousNextValues($this->tables)) {
-                $this->errormsg = 'Some TABLES previous/next values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Order tables
-            if ($result && !$this->orderTables($this->tables)) {
-                $this->errormsg = 'Error ordering the tables';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        }
-
-    /// Iterate over statements
-        if (isset($xmlarr['XMLDB']['#']['STATEMENTS']['0']['#']['STATEMENT'])) {
-            foreach ($xmlarr['XMLDB']['#']['STATEMENTS']['0']['#']['STATEMENT'] as $xmlstatement) {
-                if (!$result) { //Skip on error
-                    continue;
-                }
-                $name = trim($xmlstatement['@']['NAME']);
-                $statement = new XMLDBStatement($name);
-                $statement->arr2XMLDBStatement($xmlstatement);
-                $this->statements[] = $statement;
-                if (!$statement->isLoaded()) {
-                    $this->errormsg = 'Problem loading statement ' . $name;
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            }
-        }
-
-    /// Perform some general checks over statements
-        if ($result && $this->statements) {
-        /// Check statements names are ok (lowercase, a-z _-)
-            if (!$this->checkNameValues($this->statements)) {
-                $this->errormsg = 'Some STATEMENTS name values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Check previous & next are ok (duplicates and existing statements)
-            $this->fixPrevNext($this->statements);
-            if ($result && !$this->checkPreviousNextValues($this->statements)) {
-                $this->errormsg = 'Some STATEMENTS previous/next values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Order statements
-            if ($result && !$this->orderStatements($this->statements)) {
-                $this->errormsg = 'Error ordering the statements';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        }
-
-    /// Set some attributes
-        if ($result) {
-            $this->loaded = true;
-        }
-        $this->calculateHash();
-        return $result;
-    }
-
-    /**
-     * This function calculate and set the hash of one XMLDBStructure
-     */
-     function calculateHash($recursive = false) {
-        if (!$this->loaded) {
-            $this->hash = NULL;
-        } else {
-            $key = $this->name . $this->path . $this->comment;
-            if ($this->tables) {
-                foreach ($this->tables as $tbl) {
-                    $table =& $this->getTable($tbl->getName());
-                    if ($recursive) {
-                        $table->calculateHash($recursive);
-                    }
-                    $key .= $table->getHash();
-                }
-            }
-            if ($this->statements) {
-                foreach ($this->statements as $sta) {
-                    $statement =& $this->getStatement($sta->getName());
-                    if ($recursive) {
-                        $statement->calculateHash($recursive);
-                    }
-                    $key .= $statement->getHash();
-                }
-            }
-            $this->hash = md5($key);
-        }
-    }
-
-    /**
-     * This function will output the XML text for one structure
-     */
-    function xmlOutput() {
-        $o = '<?xml version="1.0" encoding="UTF-8" ?>' . "\n";
-        $o.= '<XMLDB PATH="' . $this->path . '"';
-        $o.= ' VERSION="' . $this->version . '"';
-        if ($this->comment) {
-            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"'."\n";
-        }
-        $rel = array_fill(0, count(explode('/', $this->path)), '..');
-        $rel = implode('/', $rel);
-        $o.= '    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'."\n";
-        $o.= '    xsi:noNamespaceSchemaLocation="'.$rel.'/lib/xmldb/xmldb.xsd"'."\n";
-        $o.= '>' . "\n";
-    /// Now the tables
-        if ($this->tables) {
-            $o.= '  <TABLES>' . "\n";
-            foreach ($this->tables as $table) {
-                $o.= $table->xmlOutput();
-            }
-            $o.= '  </TABLES>' . "\n";
-        }
-    /// Now the statements
-        if ($this->statements) {
-            $o.= '  <STATEMENTS>' . "\n";
-            foreach ($this->statements as $statement) {
-                $o.= $statement->xmlOutput();
-            }
-            $o.= '  </STATEMENTS>' . "\n";
-        }
-        $o.= '</XMLDB>';
-
-        return $o;
-    }
-
-    /**
-     * This function returns the number of uses of one table inside
-     * a whole XMLDStructure. Useful to detect if the table must be
-     * locked. Return false if no uses are found.
-     */
-    function getTableUses($tablename) {
-
-        $uses = array();
-
-    /// Check if some foreign key in the whole structure is using it
-    /// (by comparing the reftable with the tablename)
-        $alltables = $this->getTables();
-        if ($alltables) {
-            foreach ($alltables as $table) {
-                $keys = $table->getKeys();
-                if ($keys) {
-                    foreach ($keys as $key) {
-                        if ($key->getType() == XMLDB_KEY_FOREIGN) {
-                            if ($tablename == $key->getRefTable()) {
-                                $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-    /// Return result
-        if (!empty($uses)) {
-            return $uses;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * This function returns the number of uses of one field inside
-     * a whole XMLDBStructure. Useful to detect if the field must be
-     * locked. Return false if no uses are found.
-     */
-    function getFieldUses($tablename, $fieldname) {
-
-        $uses = array();
-
-    /// Check if any key in the table is using it
-        $table = $this->getTable($tablename);
-        if ($keys = $table->getKeys()) {
-            foreach ($keys as $key) {
-                if (in_array($fieldname, $key->getFields()) ||
-                    in_array($fieldname, $key->getRefFields())) {
-                        $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
-                }
-            }
-        }
-    /// Check if any index in the table is using it
-        $table = $this->getTable($tablename);
-        if ($indexes = $table->getIndexes()) {
-            foreach ($indexes as $index) {
-                if (in_array($fieldname, $index->getFields())) {
-                    $uses[] = 'table ' . $table->getName() . ' index ' . $index->getName();
-                }
-            }
-        }
-    /// Check if some foreign key in the whole structure is using it
-    /// By comparing the reftable and refields with the field)
-        $alltables = $this->getTables();
-        if ($alltables) {
-            foreach ($alltables as $table) {
-                $keys = $table->getKeys();
-                if ($keys) {
-                    foreach ($keys as $key) {
-                        if ($key->getType() == XMLDB_KEY_FOREIGN) {
-                            if ($tablename == $key->getRefTable()) {
-                                $reffieds = $key->getRefFields();
-                                if (in_array($fieldname, $key->getRefFields())) {
-                                    $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-    /// Return result
-        if (!empty($uses)) {
-            return $uses;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * This function returns the number of uses of one key inside
-     * a whole XMLDBStructure. Useful to detect if the key must be
-     * locked. Return false if no uses are found.
-     */
-    function getKeyUses($tablename, $keyname) {
-
-        $uses = array();
-
-    /// Check if some foreign key in the whole structure is using it
-    /// (by comparing the reftable and reffields with the fields in the key)
-        $mytable = $this->getTable($tablename);
-        $mykey = $mytable->getKey($keyname);
-        $alltables = $this->getTables();
-        if ($alltables && $mykey) {
-            foreach ($alltables as $table) {
-                $allkeys = $table->getKeys();
-                if ($allkeys) {
-                    foreach ($allkeys as $key) {
-                        if ($key->getType() != XMLDB_KEY_FOREIGN) {
-                            continue;
-                        }
-                        if ($key->getRefTable() == $tablename &&
-                            implode(',', $key->getRefFields()) == implode(',', $mykey->getFields())) {
-                                $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
-                        }
-                    }
-                }
-            }
-        }
-
-    /// Return result
-        if (!empty($uses)) {
-            return $uses;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * This function returns the number of uses of one index inside
-     * a whole XMLDBStructure. Useful to detect if the index must be
-     * locked. Return false if no uses are found.
-     */
-    function getIndexUses($tablename, $indexname) {
-
-        $uses = array();
-
-    /// Nothing to check, beause indexes haven't uses! Leave it here
-    /// for future checks...
-
-    /// Return result
-        if (!empty($uses)) {
-            return $uses;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * This function will return all the errors found in one structure
-     * looking recursively inside each table/statement. Returns
-     * an array of errors or false
-     */
-    function getAllErrors() {
-
-        $errors = array();
-    /// First the structure itself
-        if ($this->getError()) {
-            $errors[] = $this->getError();
-        }
-    /// Delegate to tables
-        if ($tables = $this->getTables()) {
-            foreach ($tables as $table) {
-                if ($tableerrors = $table->getAllErrors()) {
-
-                }
-            }
-        /// Add them to the errors array
-            if ($tableerrors) {
-                $errors = array_merge($errors, $tableerrors);
-            }
-        }
-    /// Delegate to statements
-        if ($statements = $this->getStatements()) {
-            foreach ($statements as $statement) {
-                if ($statement->getError()) {
-                    $errors[] = $statement->getError();
-                }
-            }
-        }
-    /// Return decision
-        if (count($errors)) {
-            return $errors;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * This function will return the SQL code needed to create the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getCreateStructureSQL ($dbtype, $prefix, $statement_end=true) {
-
-        $results = array();
-
-        if ($tables = $this->getTables()) {
-            foreach ($tables as $table) {
-                $results = array_merge($results, $table->getCreateTableSQL($dbtype, $prefix, $statement_end));
-            }
-        }
-
-        if ($statements = $this->getStatements()) {
-            foreach ($statements as $statement) {
-                $results = array_merge($results, $statement->getExecuteStatementSQL($dbtype, $prefix, $statement_end));
-            }
-        }
-        return $results;
-    }
-}
-
-?>
Index: lib/xmldb/classes/XMLDBObject.class.php
===================================================================
RCS file: lib/xmldb/classes/XMLDBObject.class.php
diff -N lib/xmldb/classes/XMLDBObject.class.php
--- lib/xmldb/classes/XMLDBObject.class.php	10 Oct 2007 05:25:14 -0000	1.7
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,450 +0,0 @@
-<?php // $Id: XMLDBObject.class.php,v 1.7 2007/10/10 05:25:14 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class represent the XMLDB base class where all the common piezes
-/// are defined
-
-class XMLDBObject {
-
-    var $name;
-    var $comment;
-    var $previous;
-    var $next;
-    var $hash;
-    var $loaded;
-    var $changed;
-    var $errormsg;
-
-    /**
-     * Creates one new XMLDBObject
-     */
-    function XMLDBObject($name) {
-        $this->name = $name;
-        $this->comment = NULL;
-        $this->previous = NULL;
-        $this->next = NULL;
-        $this->hash = NULL;
-        $this->loaded = false;
-        $this->changed = false;
-        $this->errormsg = NULL;
-    }
-
-    /**
-     * This function returns true/false, if the XMLDBObject has been loaded
-     */
-    function isLoaded() {
-        return $this->loaded;
-    }
-
-    /**
-     * This function returns true/false, if the XMLDBObject has changed
-     */
-    function hasChanged() {
-        return $this->changed;
-    }
-
-    /**
-     * This function returns the comment of one XMLDBObject
-     */
-    function getComment() {
-        return $this->comment;
-    }
-
-    /**
-     * This function returns the hash of one XMLDBObject
-     */
-    function getHash() {
-        return $this->hash;
-    }
-
-    /**
-     * This function will return the name of the previous XMLDBObject
-     */
-    function getPrevious() {
-        return $this->previous;
-    }
-
-    /**
-     * This function will return the name of the next XMLDBObject
-     */
-    function getNext() {
-        return $this->next;
-    }
-
-    /**
-     * This function will return the name of the XMLDBObject
-     */
-    function getName() {
-        return $this->name;
-    }
-
-    /**
-     * This function will return the error detected in the object
-     */
-    function getError() {
-        return $this->errormsg;
-    }
-
-    /**
-     * This function will set the comment of the XMLDB object
-     */
-    function setComment($comment) {
-        $this->comment = $comment;
-    }
-
-    /**
-     * This function will set the previous of the XMLDB object
-     */
-    function setPrevious($previous) {
-        $this->previous = $previous;
-    }
-
-    /**
-     * This function will set the next of the XMLDB object
-     */
-    function setNext($next) {
-        $this->next = $next;
-    }
-
-    /**
-     * This function will set the hash of the XMLDB object
-     */
-    function setHash($hash) {
-        $this->hash = $hash;
-    }
-
-    /**
-     * This function will set the loaded field of the XMLDB object
-     */
-    function setLoaded($loaded = true) {
-        $this->loaded = $loaded;
-    }
-
-    /**
-     * This function will set the changed field of the XMLDB object
-     */
-    function setChanged($changed = true) {
-        $this->changed = $changed;
-    }
-    /**
-     * This function will set the name field of the XMLDB object
-     */
-    function setName($name) {
-        $this->name = $name;
-    }
-
-
-    /**
-     * This function will check if one key name is ok or no (true/false)
-     * only lowercase a-z, 0-9 and _ are allowed
-     */
-    function checkName () {
-        $result = true;
-
-        if ($this->name != eregi_replace('[^a-z0-9_ -]', '', $this->name)) {
-            $result = false;
-        }
-        return $result;
-    }
-
-    /**
-     * This function will check that all the elements in one array
-     * have a correct name [a-z0-9_]
-     */
-    function checkNameValues(&$arr) {
-        $result = true;
-    /// TODO: Perhaps, add support for reserved words
-
-    /// Check the name only contains valid chars
-        if ($arr) {
-            foreach($arr as $element) {
-                if (!$element->checkName()) {
-                    $result = false;
-                }
-            }
-        }
-        return $result;
-    }
-
-    /**
-     * Reconstruct previous/next attributes.
-     */
-    function fixPrevNext(&$arr) {
-        global $CFG;
-
-        if (empty($CFG->xmldbreconstructprevnext)) {
-            return false;
-        }
-        $tweaked = false;
-
-        $prev = null;
-        foreach ($arr as $key=>$el) {
-            $prev_value = $arr[$key]->previous;
-            $next_value = $arr[$key]->next;
-
-            $arr[$key]->next     = null;
-            $arr[$key]->previous = null;
-            if ($prev !== null) {
-                $arr[$prev]->next    = $arr[$key]->name;
-                $arr[$key]->previous = $arr[$prev]->name;
-            }
-            $prev = $key;
-
-            if ($prev_value != $arr[$key]->previous or $next_value != $arr[$key]->next) {
-                $tweaked = true;
-            }
-        }
-
-        return $tweaked;
-    }
-
-    /**
-     * This function will check that all the elements in one array
-     * have a consistent info in their previous/next fields
-     */
-    function checkPreviousNextValues(&$arr) {
-        global $CFG;
-        if (!empty($CFG->xmldbdisablenextprevchecking)) {
-            return true;
-        }
-        $result = true;
-    /// Check that only one element has the previous not set
-        if ($arr) {
-            $counter = 0;
-            foreach($arr as $element) {
-                if (!$element->getPrevious()) {
-                    $counter++;
-                }
-            }
-            if ($counter != 1) {
-                $result = false;
-            }
-        }
-    /// Check that only one element has the next not set
-        if ($result && $arr) {
-            $counter = 0;
-            foreach($arr as $element) {
-                if (!$element->getNext()) {
-                    $counter++;
-                }
-            }
-            if ($counter != 1) {
-                $result = false;
-            }
-        }
-    /// Check that all the previous elements are existing elements
-        if ($result && $arr) {
-            foreach($arr as $element) {
-                if ($element->getPrevious()) {
-                    $i = $this->findObjectInArray($element->getPrevious(), $arr);
-                    if ($i === NULL) {
-                        $result = false;
-                    }
-                }
-            }
-        }
-    /// Check that all the next elements are existing elements
-        if ($result && $arr) {
-            foreach($arr as $element) {
-                if ($element->getNext()) {
-                    $i = $this->findObjectInArray($element->getNext(), $arr);
-                    if ($i === NULL) {
-                        $result = false;
-                    }
-                }
-            }
-        }
-    /// Check that there aren't duplicates in the previous values
-        if ($result && $arr) {
-            $existarr = array();
-            foreach($arr as $element) {
-                if (in_array($element->getPrevious(), $existarr)) {
-                    $result = false;
-                } else {
-                    $existarr[] = $element->getPrevious();
-                }
-            }
-        }
-    /// Check that there aren't duplicates in the next values
-        if ($result && $arr) {
-            $existarr = array();
-            foreach($arr as $element) {
-                if (in_array($element->getNext(), $existarr)) {
-                    $result = false;
-                } else {
-                    $existarr[] = $element->getNext();
-                }
-            }
-        }
-        return $result;
-    }
-
-    /**
-     * This function will order all the elements in one array, following
-     * the previous/next rules
-     */
-    function orderElements($arr) {
-        global $CFG;
-        $result = true;
-        if (!empty($CFG->xmldbdisablenextprevchecking)) {
-            return $arr;
-        }
-    /// Create a new array
-        $newarr = array();
-        if (!empty($arr)) {
-            $currentelement = NULL;
-        /// Get the element without previous
-            foreach($arr as $key => $element) {
-                if (!$element->getPrevious()) {
-                    $currentelement = $arr[$key];
-                    $newarr[0] = $arr[$key];
-                }
-            }
-            if (!$currentelement) {
-                $result = false;
-            }
-        /// Follow the next rules
-            $counter = 1;
-            while ($result && $currentelement->getNext()) {
-                $i = $this->findObjectInArray($currentelement->getNext(), $arr);
-                $currentelement = $arr[$i];
-                $newarr[$counter] = $arr[$i];
-                $counter++;
-            }
-        /// Compare number of elements between original and new array
-            if ($result && count($arr) != count($newarr)) {
-                $result = false;
-            }
-        /// Check that previous/next is ok (redundant but...)
-            if ($this->checkPreviousNextValues($newarr)) {
-                $result = $newarr;
-            } else {
-                $result = false;
-            }
-        } else {
-            $result = array();
-        }
-        return $result;
-    }
-
-    /**
-     * Returns the position of one object in the array.
-     */
-    function &findObjectInArray($objectname, $arr) {
-        foreach ($arr as $i => $object) {
-            if ($objectname == $object->getName()) {
-                return $i;
-            }
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * This function will display a readable info about the XMLDBObject
-     * (should be implemented inside each XMLDBxxx object)
-     */
-    function readableInfo() {
-        return get_class($this);
-    }
-
-    /**
-     * This function will perform the central debug of all the XMLDB classes
-     * being called automatically every time one error is found. Apart from 
-     * the main actions performed in it (XMLDB agnostic) it looks for one
-     * function called xmldb_debug() and invokes it, passing both the
-     * message code and the whole object. 
-     * So, to perform custom debugging just add such function to your libs.
-     * 
-     * Call to the external hook function can be disabled by request by
-     * defining XMLDB_SKIP_DEBUG_HOOK
-     */
-    function debug($message) {
-
-    /// Check for xmldb_debug($message, $xmldb_object)
-        $funcname = 'xmldb_debug';
-    /// If exists and XMLDB_SKIP_DEBUG_HOOK is undefined
-        if (function_exists($funcname) && !defined('XMLDB_SKIP_DEBUG_HOOK')) {
-            $funcname($message, $this);
-        }
-    }
-
-    /**
-     * Returns one array of elements from one comma separated string,
-     * supporting quoted strings containing commas and concat function calls
-     */
-    function comma2array($string) {
-
-        $arr = array();
-
-        $foundquotes  = array();
-        $foundconcats = array();
-
-    /// Extract all the concat elements from the string
-        preg_match_all("/(CONCAT\(.*?\))/is", $string, $matches);
-        foreach (array_unique($matches[0]) as $key=>$value) {
-            $foundconcats['<#'.$key.'#>'] = $value;
-        }
-        if (!empty($foundconcats)) {
-            $string = str_replace($foundconcats,array_keys($foundconcats),$string);
-        }
-
-    /// Extract all the quoted elements from the string (skipping 
-    /// backslashed quotes that are part of the content.
-        preg_match_all("/('.*?[^\\\]')/is", $string, $matches);
-        foreach (array_unique($matches[0]) as $key=>$value) {
-            $foundquotes['<%'.$key.'%>'] = $value;
-        }
-        if (!empty($foundquotes)) {
-            $string = str_replace($foundquotes,array_keys($foundquotes),$string);
-        }
-
-    /// Explode safely the string
-        $arr = explode (',', $string);
-
-    /// Put the concat and quoted elements back again, triming every element
-        if ($arr) {
-            foreach ($arr as $key => $element) {
-            /// Clear some spaces
-                $element = trim($element);
-            /// Replace the quoted elements if exists
-                if (!empty($foundquotes)) {
-                    $element = str_replace(array_keys($foundquotes), $foundquotes, $element);
-                }
-            /// Replace the concat elements if exists
-                if (!empty($foundconcats)) {
-                    $element = str_replace(array_keys($foundconcats), $foundconcats, $element);
-                }
-            /// Delete any backslash used for quotes. XMLDB stuff will add them before insert
-                $arr[$key] = str_replace("\\'", "'", $element);
-            }
-        }
-
-        return $arr;
-    }
-}
-
-?>
Index: lib/xmldb/classes/XMLDBTable.class.php
===================================================================
RCS file: lib/xmldb/classes/XMLDBTable.class.php
diff -N lib/xmldb/classes/XMLDBTable.class.php
--- lib/xmldb/classes/XMLDBTable.class.php	10 Oct 2007 05:25:14 -0000	1.22
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,1080 +0,0 @@
-<?php // $Id: XMLDBTable.class.php,v 1.22 2007/10/10 05:25:14 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class represent one XMLDB table
-
-class XMLDBTable extends XMLDBObject {
-
-    var $fields;
-    var $keys;
-    var $indexes;
-
-    /**
-     * Creates one new XMLDBTable
-     */
-    function XMLDBTable($name) {
-        parent::XMLDBObject($name);
-        $this->fields = array();
-        $this->keys = array();
-        $this->indexes = array();
-    }
-
-    /**
-     * Add one field to the table, allowing to specify the desired  order
-     * If it's not specified, then the field is added at the end
-     */
-    function addField(&$field, $after=NULL) {
-
-    /// Calculate the previous and next fields
-        $prevfield = NULL;
-        $nextfield = NULL;
-
-        if (!$after) {
-            $allfields =& $this->getFields();
-            if (!empty($allfields)) {
-                end($allfields);
-                $prevfield =& $allfields[key($allfields)];
-            }
-        } else {
-            $prevfield =& $this->getField($after);
-        }
-        if ($prevfield && $prevfield->getNext()) {
-            $nextfield =& $this->getField($prevfield->getNext());
-        }
-
-    /// Set current field previous and next attributes
-        if ($prevfield) {
-            $field->setPrevious($prevfield->getName());
-            $prevfield->setNext($field->getName());
-        }
-        if ($nextfield) {
-            $field->setNext($nextfield->getName());
-            $nextfield->setPrevious($field->getName());
-        }
-    /// Some more attributes
-        $field->setLoaded(true);
-        $field->setChanged(true);
-    /// Add the new field
-        $this->fields[] = $field;
-    /// Reorder the field
-        $this->orderFields($this->fields);
-    /// Recalculate the hash
-        $this->calculateHash(true);
-    /// We have one new field, so the table has changed
-        $this->setChanged(true);
-
-        return $field;
-    }
-
-    /**
-     * Add one key to the table, allowing to specify the desired  order
-     * If it's not specified, then the key is added at the end
-     */
-    function addKey(&$key, $after=NULL) {
-
-    /// Calculate the previous and next keys
-        $prevkey = NULL;
-        $nextkey = NULL;
-
-        if (!$after) {
-            $allkeys =& $this->getKeys();
-            if (!empty($allkeys)) {
-                end($allkeys);
-                $prevkey =& $allkeys[key($allkeys)];
-            }
-        } else {
-            $prevkey =& $this->getKey($after);
-        }
-        if ($prevkey && $prevkey->getNext()) {
-            $nextkey =& $this->getKey($prevkey->getNext());
-        }
-
-    /// Set current key previous and next attributes
-        if ($prevkey) {
-            $key->setPrevious($prevkey->getName());
-            $prevkey->setNext($key->getName());
-        }
-        if ($nextkey) {
-            $key->setNext($nextkey->getName());
-            $nextkey->setPrevious($key->getName());
-        }
-    /// Some more attributes
-        $key->setLoaded(true);
-        $key->setChanged(true);
-    /// Add the new key
-        $this->keys[] = $key;
-    /// Reorder the keys
-        $this->orderKeys($this->keys);
-    /// Recalculate the hash
-        $this->calculateHash(true);
-    /// We have one new field, so the table has changed
-        $this->setChanged(true);
-    }
-
-    /**
-     * Add one index to the table, allowing to specify the desired  order
-     * If it's not specified, then the index is added at the end
-     */
-    function addIndex(&$index, $after=NULL) {
-
-    /// Calculate the previous and next indexes
-        $previndex = NULL;
-        $nextindex = NULL;
-
-        if (!$after) {
-            $allindexes =& $this->getIndexes();
-            if (!empty($allindexes)) {
-                end($allindexes);
-                $previndex =& $allindexes[key($allindexes)];
-            }
-        } else {
-            $previndex =& $this->getIndex($after);
-        }
-        if ($previndex && $previndex->getNext()) {
-            $nextindex =& $this->getIndex($previndex->getNext());
-        }
-
-    /// Set current index previous and next attributes
-        if ($previndex) {
-            $index->setPrevious($previndex->getName());
-            $previndex->setNext($index->getName());
-        }
-        if ($nextindex) {
-            $index->setNext($nextindex->getName());
-            $nextindex->setPrevious($index->getName());
-        }
-
-    /// Some more attributes
-        $index->setLoaded(true);
-        $index->setChanged(true);
-    /// Add the new index
-        $this->indexes[] = $index;
-    /// Reorder the indexes
-        $this->orderIndexes($this->indexes);
-    /// Recalculate the hash
-        $this->calculateHash(true);
-    /// We have one new index, so the table has changed
-        $this->setChanged(true);
-    }
-
-    /**
-     * This function will return the array of fields in the table
-     */
-    function &getFields() {
-        return $this->fields;
-    }
-
-    /**
-     * This function will return the array of keys in the table
-     */
-    function &getKeys() {
-        return $this->keys;
-    }
-
-    /**
-     * This function will return the array of indexes in the table
-     */
-    function &getIndexes() {
-        return $this->indexes;
-    }
-
-    /**
-     * Returns one XMLDBField
-     */
-    function &getField($fieldname) {
-        $i = $this->findFieldInArray($fieldname);
-        if ($i !== NULL) {
-            return $this->fields[$i];
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * Returns the position of one field in the array.
-     */
-    function &findFieldInArray($fieldname) {
-        foreach ($this->fields as $i => $field) {
-            if ($fieldname == $field->getName()) {
-                return $i;
-            }
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * This function will reorder the array of fields
-     */
-    function orderFields() {
-        $result = $this->orderElements($this->fields);
-        if ($result) {
-            $this->setFields($result);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Returns one XMLDBKey
-     */
-    function &getKey($keyname) {
-        $i = $this->findKeyInArray($keyname);
-        if ($i !== NULL) {
-            return $this->keys[$i];
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * Returns the position of one key in the array.
-     */
-    function &findKeyInArray($keyname) {
-        foreach ($this->keys as $i => $key) {
-            if ($keyname == $key->getName()) {
-                return $i;
-            }
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * This function will reorder the array of keys
-     */
-    function orderKeys() {
-        $result = $this->orderElements($this->keys);
-        if ($result) {
-            $this->setKeys($result);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Returns one XMLDBIndex
-     */
-    function &getIndex($indexname) {
-        $i = $this->findIndexInArray($indexname);
-        if ($i !== NULL) {
-            return $this->indexes[$i];
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * Returns the position of one index in the array.
-     */
-    function &findIndexInArray($indexname) {
-        foreach ($this->indexes as $i => $index) {
-            if ($indexname == $index->getName()) {
-                return $i;
-            }
-        }
-        $null = NULL;
-        return $null;
-    }
-
-    /**
-     * This function will reorder the array of indexes
-     */
-    function orderIndexes() {
-        $result = $this->orderElements($this->indexes);
-        if ($result) {
-            $this->setIndexes($result);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * This function will set the array of fields in the table
-     */
-    function setFields($fields) {
-        $this->fields = $fields;
-    }
-
-    /**
-     * This function will set the array of keys in the table
-     */
-    function setKeys($keys) {
-        $this->keys = $keys;
-    }
-
-    /**
-     * This function will set the array of indexes in the table
-     */
-    function setIndexes($indexes) {
-        $this->indexes = $indexes;
-    }
-
-    /**
-     * Delete one field from the table
-     */
-    function deleteField($fieldname) {
-
-        $field =& $this->getField($fieldname);
-        if ($field) {
-            $i = $this->findFieldInArray($fieldname);
-            $prevfield = NULL;
-            $nextfield = NULL;
-        /// Look for prev and next field
-            $prevfield =& $this->getField($field->getPrevious());
-            $nextfield =& $this->getField($field->getNext());
-        /// Change their previous and next attributes
-            if ($prevfield) {
-                $prevfield->setNext($field->getNext());
-            }
-            if ($nextfield) {
-                $nextfield->setPrevious($field->getPrevious());
-            }
-        /// Delete the field
-            unset($this->fields[$i]);
-        /// Reorder the whole structure
-            $this->orderFields($this->fields);
-        /// Recalculate the hash
-            $this->calculateHash(true);
-        /// We have one deleted field, so the table has changed
-            $this->setChanged(true);
-        }
-    }
-
-    /**
-     * Delete one key from the table
-     */
-    function deleteKey($keyname) {
-
-        $key =& $this->getKey($keyname);
-        if ($key) {
-            $i = $this->findKeyInArray($keyname);
-            $prevkey = NULL;
-            $nextkey = NULL;
-        /// Look for prev and next key
-            $prevkey =& $this->getKey($key->getPrevious());
-            $nextkey =& $this->getKey($key->getNext());
-        /// Change their previous and next attributes
-            if ($prevkey) {
-                $prevkey->setNext($key->getNext());
-            }
-            if ($nextkey) {
-                $nextkey->setPrevious($key->getPrevious());
-            }
-        /// Delete the key
-            unset($this->keys[$i]);
-        /// Reorder the Keys
-            $this->orderKeys($this->keys);
-        /// Recalculate the hash
-            $this->calculateHash(true);
-        /// We have one deleted key, so the table has changed
-            $this->setChanged(true);
-        }
-    }
-
-    /**
-     * Delete one index from the table
-     */
-    function deleteIndex($indexname) {
-
-        $index =& $this->getIndex($indexname);
-        if ($index) {
-            $i = $this->findIndexInArray($indexname);
-            $previndex = NULL;
-            $nextindex = NULL;
-        /// Look for prev and next index
-            $previndex =& $this->getIndex($index->getPrevious());
-            $nextindex =& $this->getIndex($index->getNext());
-        /// Change their previous and next attributes
-            if ($previndex) {
-                $previndex->setNext($index->getNext());
-            }
-            if ($nextindex) {
-                $nextindex->setPrevious($index->getPrevious());
-            }
-        /// Delete the index
-            unset($this->indexes[$i]);
-        /// Reorder the indexes
-            $this->orderIndexes($this->indexes);
-        /// Recalculate the hash
-            $this->calculateHash(true);
-        /// We have one deleted index, so the table has changed
-            $this->setChanged(true);
-        }
-    }
-
-    /**
-     * Load data from XML to the table
-     */
-    function arr2XMLDBTable($xmlarr) {
-
-        global $CFG;
-
-        $result = true;
-
-    /// Debug the table
-    /// traverse_xmlize($xmlarr);                   //Debug
-    /// print_object ($GLOBALS['traverse_array']);  //Debug
-    /// $GLOBALS['traverse_array']="";              //Debug
-
-    /// Process table attributes (name, comment, previoustable and nexttable)
-        if (isset($xmlarr['@']['NAME'])) {
-            $this->name = trim($xmlarr['@']['NAME']);
-        } else {
-            $this->errormsg = 'Missing NAME attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-        if (isset($xmlarr['@']['COMMENT'])) {
-            $this->comment = trim($xmlarr['@']['COMMENT']);
-        } else if (!empty($CFG->xmldbdisablecommentchecking)) {
-            $this->comment = '';
-        } else {
-            $this->errormsg = 'Missing COMMENT attribute';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-        if (isset($xmlarr['@']['PREVIOUS'])) {
-            $this->previous = trim($xmlarr['@']['PREVIOUS']);
-        }
-        if (isset($xmlarr['@']['NEXT'])) {
-            $this->next = trim($xmlarr['@']['NEXT']);
-        }
-
-    /// Iterate over fields
-        if (isset($xmlarr['#']['FIELDS']['0']['#']['FIELD'])) {
-            foreach ($xmlarr['#']['FIELDS']['0']['#']['FIELD'] as $xmlfield) {
-                if (!$result) { //Skip on error
-                    continue;
-                }
-                $name = trim($xmlfield['@']['NAME']);
-                $field = new XMLDBField($name);
-                $field->arr2XMLDBField($xmlfield);
-                $this->fields[] = $field;
-                if (!$field->isLoaded()) {
-                    $this->errormsg = 'Problem loading field ' . $name;
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            }
-        } else {
-            $this->errormsg = 'Missing FIELDS section';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-    /// Perform some general checks over fields
-        if ($result && $this->fields) {
-        /// Check field names are ok (lowercase, a-z _-)
-            if (!$this->checkNameValues($this->fields)) {
-                $this->errormsg = 'Some FIELDS name values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Check previous & next are ok (duplicates and existing fields)
-            $this->fixPrevNext($this->fields);
-            if ($result && !$this->checkPreviousNextValues($this->fields)) {
-                $this->errormsg = 'Some FIELDS previous/next values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Order fields
-            if ($result && !$this->orderFields($this->fields)) {
-                $this->errormsg = 'Error ordering the fields';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        }
-
-    /// Iterate over keys
-        if (isset($xmlarr['#']['KEYS']['0']['#']['KEY'])) {
-            foreach ($xmlarr['#']['KEYS']['0']['#']['KEY'] as $xmlkey) {
-                if (!$result) { //Skip on error
-                    continue;
-                }
-                $name = trim($xmlkey['@']['NAME']);
-                $key = new XMLDBKey($name);
-                $key->arr2XMLDBKey($xmlkey);
-                $this->keys[] = $key;
-                if (!$key->isLoaded()) {
-                    $this->errormsg = 'Problem loading key ' . $name;
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            }
-        } else {
-            $this->errormsg = 'Missing KEYS section (at least one PK must exist)';
-            $this->debug($this->errormsg);
-            $result = false;
-        }
-
-    /// Perform some general checks over keys
-        if ($result && $this->keys) {
-        /// Check keys names are ok (lowercase, a-z _-)
-            if (!$this->checkNameValues($this->keys)) {
-                $this->errormsg = 'Some KEYS name values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Check previous & next are ok (duplicates and existing keys)
-            $this->fixPrevNext($this->keys);
-            if ($result && !$this->checkPreviousNextValues($this->keys)) {
-                $this->errormsg = 'Some KEYS previous/next values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Order keys
-            if ($result && !$this->orderKeys($this->keys)) {
-                $this->errormsg = 'Error ordering the keys';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// TODO: Only one PK
-        /// TODO: Not keys with repeated fields
-        /// TODO: Check fields and reffieds exist in table
-        }
-
-    /// Iterate over indexes
-        if (isset($xmlarr['#']['INDEXES']['0']['#']['INDEX'])) {
-            foreach ($xmlarr['#']['INDEXES']['0']['#']['INDEX'] as $xmlindex) {
-                if (!$result) { //Skip on error
-                    continue;
-                }
-                $name = trim($xmlindex['@']['NAME']);
-                $index = new XMLDBIndex($name);
-                $index->arr2XMLDBIndex($xmlindex);
-                $this->indexes[] = $index;
-                if (!$index->isLoaded()) {
-                    $this->errormsg = 'Problem loading index ' . $name;
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
-            }
-        }
-
-    /// Perform some general checks over indexes
-        if ($result && $this->indexes) {
-        /// Check field names are ok (lowercase, a-z _-)
-            if (!$this->checkNameValues($this->indexes)) {
-                $this->errormsg = 'Some INDEXES name values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Check previous & next are ok (duplicates and existing INDEXES)
-            $this->fixPrevNext($this->indexes);
-            if ($result && !$this->checkPreviousNextValues($this->indexes)) {
-                $this->errormsg = 'Some INDEXES previous/next values are incorrect';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// Order indexes
-            if ($result && !$this->orderIndexes($this->indexes)) {
-                $this->errormsg = 'Error ordering the indexes';
-                $this->debug($this->errormsg);
-                $result = false;
-            }
-        /// TODO: Not indexes with repeated fields
-        /// TODO: Check fields exist in table
-        }
-
-    /// Set some attributes
-        if ($result) {
-            $this->loaded = true;
-        }
-        $this->calculateHash();
-        return $result;
-    }
-
-    /**
-     * This function calculate and set the hash of one XMLDBTable
-     */
-     function calculateHash($recursive = false) {
-        if (!$this->loaded) {
-            $this->hash = NULL;
-        } else {
-            $key = $this->name . $this->comment;
-            if ($this->fields) {
-                foreach ($this->fields as $fie) {
-                    $field =& $this->getField($fie->getName());
-                    if ($recursive) {
-                        $field->calculateHash($recursive);
-                    }
-                    $key .= $field->getHash();
-                }
-            }
-            if ($this->keys) {
-                foreach ($this->keys as $ke) {
-                    $k =& $this->getKey($ke->getName());
-                    if ($recursive) {
-                        $k->calculateHash($recursive);
-                    }
-                    $key .= $k->getHash();
-                }
-            }
-            if ($this->indexes) {
-                foreach ($this->indexes as $in) {
-                    $index =& $this->getIndex($in->getName());
-                    if ($recursive) {
-                        $index->calculateHash($recursive);
-                    }
-                    $key .= $index->getHash();
-                }
-            }
-            $this->hash = md5($key);
-        }
-    }
-
-    /**
-     * This function will output the XML text for one table
-     */
-    function xmlOutput() {
-        $o = '';
-        $o.= '    <TABLE NAME="' . $this->name . '"';
-        if ($this->comment) {
-            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
-        }
-        if ($this->previous) {
-            $o.= ' PREVIOUS="' . $this->previous . '"';
-        }
-        if ($this->next) {
-            $o.= ' NEXT="' . $this->next . '"';
-        }
-            $o.= '>' . "\n";
-    /// Now the fields
-        if ($this->fields) {
-            $o.= '      <FIELDS>' . "\n";
-            foreach ($this->fields as $field) {
-                $o.= $field->xmlOutput();
-            }
-            $o.= '      </FIELDS>' . "\n";
-        }
-    /// Now the keys
-        if ($this->keys) {
-            $o.= '      <KEYS>' . "\n";
-            foreach ($this->keys as $key) {
-                $o.= $key->xmlOutput();
-            }
-            $o.= '      </KEYS>' . "\n";
-        }
-    /// Now the indexes
-        if ($this->indexes) {
-            $o.= '      <INDEXES>' . "\n";
-            foreach ($this->indexes as $index) {
-                $o.= $index->xmlOutput();
-            }
-            $o.= '      </INDEXES>' . "\n";
-        }
-        $o.= '    </TABLE>' . "\n";
-
-        return $o;
-    }
-
-    /**
-     * This function will add one new field to the table with all
-     * its attributes defined
-     *
-     * @param string name name of the field
-     * @param string type XMLDB_TYPE_INTEGER, XMLDB_TYPE_NUMBER, XMLDB_TYPE_CHAR, XMLDB_TYPE_TEXT, XMLDB_TYPE_BINARY
-     * @param string precision length for integers and chars, two-comma separated numbers for numbers and 'small', 'medium', 'big' for texts and binaries
-     * @param string unsigned XMLDB_UNSIGNED or null (or false)
-     * @param string notnull XMLDB_NOTNULL or null (or false)
-     * @param string sequence XMLDB_SEQUENCE or null (or false)
-     * @param string enum XMLDB_ENUM or null (or false)
-     * @param array enumvalues an array of possible values if XMLDB_ENUM is set
-     * @param string default meaningful default o null (or false)
-     * @param string previous name of the previous field in the table or null (or false)
-     */
-    function addFieldInfo($name, $type, $precision=null, $unsigned=null, $notnull=null, $sequence=null, $enum=null, $enumvalues=null, $default=null, $previous=null) {
-        $field = new XMLDBField($name);
-        $field->setAttributes($type, $precision, $unsigned, $notnull, $sequence, $enum, $enumvalues, $default);
-        $this->addField($field, $previous);
-
-        return $field;
-    }
-
-    /**
-     * This function will add one new key to the table with all
-     * its attributes defined
-     *
-     * @param string name name of the key
-     * @param string type XMLDB_KEY_PRIMARY, XMLDB_KEY_UNIQUE, XMLDB_KEY_FOREIGN
-     * @param array fields an array of fieldnames to build the key over
-     * @param string reftable name of the table the FK points to or null
-     * @param array reffields an array of fieldnames in the FK table or null
-     */
-    function addKeyInfo($name, $type, $fields, $reftable=null, $reffields=null) {
-        $key = new XMLDBKey($name);
-        $key->setAttributes($type, $fields, $reftable, $reffields);
-        $this->addKey($key);
-    }
-
-    /**
-     * This function will add one new index to the table with all
-     * its attributes defined
-     *
-     * @param string name name of the index
-     * @param string type XMLDB_INDEX_UNIQUE, XMLDB_INDEX_NOTUNIQUE
-     * @param array fields an array of fieldnames to build the index over
-     */
-    function addIndexInfo($name, $type, $fields) {
-        $index = new XMLDBIndex($name);
-        $index->setAttributes($type, $fields);
-        $this->addIndex($index);
-    }
-
-    /**
-     * This function will return all the errors found in one table
-     * looking recursively inside each field/key/index. Returns
-     * an array of errors or false
-     */
-    function getAllErrors() {
-
-        $errors = array();
-    /// First the table itself
-        if ($this->getError()) {
-            $errors[] = $this->getError();
-        }
-    /// Delegate to fields
-        if ($fields = $this->getFields()) {
-            foreach ($fields as $field) {
-                if ($field->getError()) {
-                    $errors[] = $field->getError();
-                }
-            }
-        }
-    /// Delegate to keys
-        if ($keys = $this->getKeys()) {
-            foreach ($keys as $key) {
-                if ($key->getError()) {
-                    $errors[] = $key->getError();
-                }
-            }
-        }
-    /// Delegate to indexes
-        if ($indexes = $this->getIndexes()) {
-            foreach ($indexes as $index) {
-                if ($index->getError()) {
-                    $errors[] = $index->getError();
-                }
-            }
-        }
-    /// Return decision
-        if (count($errors)) {
-            return $errors;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * This function will return the SQL code needed to create the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getCreateTableSQL ($dbtype, $prefix, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getCreateTableSQL($this);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to create the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getRenameTableSQL ($dbtype, $prefix, $newname, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getRenameTableSQL($this, $newname);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to drop the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getDropTableSQL ($dbtype, $prefix, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getDropTableSQL($this);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to add one field to the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getAddFieldSQL ($dbtype, $prefix, $xmldb_field, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getAddFieldSQL($this, $xmldb_field);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to drop one field from the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getDropFieldSQL ($dbtype, $prefix, $xmldb_field, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getDropFieldSQL($this, $xmldb_field);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to rename one field from the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getRenameFieldSQL ($dbtype, $prefix, $xmldb_field, $newname, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getRenameFieldSQL($this, $xmldb_field, $newname);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to alter one field in the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getAlterFieldSQL ($dbtype, $prefix, $xmldb_field, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getAlterFieldSQL($this, $xmldb_field);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to modify the enum of one field in the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getModifyEnumSQL ($dbtype, $prefix, $xmldb_field, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getModifyEnumSQL($this, $xmldb_field);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to modify the default of one field in the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getModifyDefaultSQL ($dbtype, $prefix, $xmldb_field, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getModifyDefaultSQL($this, $xmldb_field);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to add one key to the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getAddKeySQL ($dbtype, $prefix, $xmldb_key, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getAddKeySQL($this, $xmldb_key);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to drop one key from the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getDropKeySQL ($dbtype, $prefix, $xmldb_key, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getDropKeySQL($this, $xmldb_key);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to rename one key from the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getRenameKeySQL ($dbtype, $prefix, $xmldb_key, $newname, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getRenameKeySQL($this, $xmldb_key, $newname);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to add one index to the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getAddIndexSQL ($dbtype, $prefix, $xmldb_index, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getAddIndexSQL($this, $xmldb_index);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to drop one index from the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     */
-    function getDropIndexSQL ($dbtype, $prefix, $xmldb_index, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getDropIndexSQL($this, $xmldb_index);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the SQL code needed to rename one index from the table for the specified DB and
-     * prefix. Just one simple wrapper over generators.
-     * Experimental. Shouldn't be used at all!
-     */
-    function getRenameIndexSQL ($dbtype, $prefix, $xmldb_index, $newname, $statement_end=true) {
-
-        $results = array();
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        $results = $generator->getRenameIndexSQL($this, $xmldb_index, $newname);
-        if ($statement_end) {
-            $results = $generator->getEndedStatements($results);
-        }
-        return $results;
-    }
-
-    /**
-     * This function will return the name of the sequence created for the pk of the table specified
-     * Just one simple wrapper over generators. Returns false if not found
-     * Note that not all DB use sequences (only Oracle and PostgreSQL)
-     */
-    function getSequenceFromDB($dbtype, $prefix) {
-
-        $classname = 'XMLDB' . $dbtype;
-        $generator = new $classname();
-        $generator->setPrefix($prefix);
-        return $generator->getSequenceFromDB($this);
-    }
-}
-
-?>
Index: mod/feedback/db/upgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/feedback/db/upgrade.php,v
retrieving revision 1.7
diff -u -r1.7 upgrade.php
--- mod/feedback/db/upgrade.php	14 May 2008 22:34:01 -0000	1.7
+++ mod/feedback/db/upgrade.php	15 May 2008 21:11:24 -0000
@@ -19,7 +19,9 @@
 
 function xmldb_feedback_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
+
+    $dbman = $DB->get_manager();
 
     $result = true;
 
@@ -56,7 +58,7 @@
         $key->setAttributes(XMLDB_KEY_FOREIGN, array('feedback'), 'feedback', 'id');
         $table->addKey($key);
 
-        $result = $result && create_table($table);
+        $result = $result && $dbman->create_table($table);
         ////////////////////////////////////////////////////////////
         ////////////////////////////////////////////////////////////
         //create a new table feedback_valuetmp and the field-definition
@@ -94,7 +96,7 @@
         $key->setAttributes(XMLDB_KEY_FOREIGN, array('item'), 'feedback_item', 'id');
         $table->addKey($key);
 
-        $result = $result && create_table($table);
+        $result = $result && $dbman->create_table($table);
         ////////////////////////////////////////////////////////////
     }
 
@@ -105,28 +107,28 @@
         $field = new XMLDBField('random_response');
         $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, false, null, null, '0', null);
         /// Launch add field1
-        $result = $result && add_field($table, $field);
+        $result = $result && $dbman->add_field($table, $field);
 
         /// Define field anonymous_response to be added to feedback_completed
         $table = new XMLDBTable('feedback_completed');
         $field = new XMLDBField('anonymous_response');
         $field->setAttributes(XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, false, null, null, '1', null);
         /// Launch add field2
-        $result = $result && add_field($table, $field);
+        $result = $result && $dbman->add_field($table, $field);
 
         /// Define field random_response to be added to feedback_completed
         $table = new XMLDBTable('feedback_completedtmp');
         $field = new XMLDBField('random_response');
         $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, false, null, null, '0', null);
         /// Launch add field1
-        $result = $result && add_field($table, $field);
+        $result = $result && $dbman->add_field($table, $field);
 
         /// Define field anonymous_response to be added to feedback_completed
         $table = new XMLDBTable('feedback_completedtmp');
         $field = new XMLDBField('anonymous_response');
         $field->setAttributes(XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, false, null, null, '1', null);
         /// Launch add field2
-        $result = $result && add_field($table, $field);
+        $result = $result && $dbman->add_field($table, $field);
 
         ////////////////////////////////////////////////////////////
     }
@@ -136,39 +138,40 @@
 
         $table = new XMLDBTable('feedback_template');
         $field = new XMLDBField('ispublic');
-        if (!field_exists($table, $field)) {
-            $result = $result && table_column('feedback_template', 'public', 'ispublic', 'integer', 1);
+        $field->setAttributes(XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, false, null, null, '1', null);
+        if (!$dbman->field_exists($table, $field)) {
+            $result = $result && $dbman->add_field($table, $field);
         }
     }
 
     if ($result && $oldversion < 2008042400) { //New version in version.php
-        if($all_nonanonymous_feedbacks = get_records('feedback', 'anonymous', 2)) {
-            $update_sql = 'UPDATE '.$CFG->prefix.'feedback_completed SET anonymous_response = 2 WHERE feedback = ';
+        if ($all_nonanonymous_feedbacks = $DB->get_records('feedback', 'anonymous', 2)) {
+            $update_sql = 'UPDATE {feedback_completed} SET anonymous_response = 2 WHERE feedback = ';
             foreach ($all_nonanonymous_feedbacks as $fb) {
-                $result = $result && execute_sql($update_sql.$fb->id);
+                $result = $result && $DB->execute($update_sql.$fb->id);
             }
         }
     }
 
     if ($result && $oldversion < 2008042401) { //New version in version.php
-        if($result) {
-            $concat_radio = sql_concat("'r>>>>>'",'presentation');
-            $concat_check = sql_concat("'d>>>>>'",'presentation');
-            $concat_dropdown = sql_concat("'c>>>>>'",'presentation');
+        if ($result) {
+            $concat_radio    = $DB->sql_concat("'r>>>>>'",'presentation');
+            $concat_check    = $DB->sql_concat("'d>>>>>'",'presentation');
+            $concat_dropdown = $DB->sql_concat("'c>>>>>'",'presentation');
             
-            $update_sql1 = "UPDATE ".$CFG->prefix."feedback_item SET presentation = ".$concat_radio." WHERE typ IN('radio','radiorated')";
-            $update_sql2 = "UPDATE ".$CFG->prefix."feedback_item SET presentation = ".$concat_dropdown." WHERE typ IN('dropdown','dropdownrated')";
-            $update_sql3 = "UPDATE ".$CFG->prefix."feedback_item SET presentation = ".$concat_check." WHERE typ = 'check'";
+            $update_sql1 = "UPDATE {feedback_item} SET presentation = ".$concat_radio." WHERE typ IN('radio','radiorated')";
+            $update_sql2 = "UPDATE {feedback_item} SET presentation = ".$concat_dropdown." WHERE typ IN('dropdown','dropdownrated')";
+            $update_sql3 = "UPDATE {feedback_item} SET presentation = ".$concat_check." WHERE typ = 'check'";
             
-            $result = $result && execute_sql($update_sql1);
-            $result = $result && execute_sql($update_sql2);
-            $result = $result && execute_sql($update_sql3);
+            $result = $result && $DB->execute($update_sql1);
+            $result = $result && $DB->execute($update_sql2);
+            $result = $result && $BB->execute($update_sql3);
         }
-        if($result) {
-            $update_sql1 = "UPDATE ".$CFG->prefix."feedback_item SET typ = 'multichoice' WHERE typ IN('radio','check','dropdown')";
-            $update_sql2 = "UPDATE ".$CFG->prefix."feedback_item SET typ = 'multichoicerated' WHERE typ IN('radiorated','dropdownrated')";
-            $result = $result && execute_sql($update_sql1);            
-            $result = $result && execute_sql($update_sql2);            
+        if ($result) {
+            $update_sql1 = "UPDATE {feedback_item} SET typ = 'multichoice' WHERE typ IN('radio','check','dropdown')";
+            $update_sql2 = "UPDATE {feedback_item} SET typ = 'multichoicerated' WHERE typ IN('radiorated','dropdownrated')";
+            $result = $result && $DB->execute($update_sql1);            
+            $result = $result && $DB->execute($update_sql2);            
         }
     }
 
@@ -178,25 +181,25 @@
         $new_log_display->action = 'startcomplete';
         $new_log_display->mtable = 'feedback';
         $new_log_display->field = 'name';
-        $result = $result && insert_record('log_display', $new_log_display);
+        $result = $result && $DB->insert_record('log_display', $new_log_display);
         
         $new_log_display = clone($new_log_display);
         $new_log_display->action = 'submit';
-        $result = $result && insert_record('log_display', $new_log_display);
+        $result = $result && $DB->insert_record('log_display', $new_log_display);
         
         $new_log_display = clone($new_log_display);
         $new_log_display->action = 'delete';
-        $result = $result && insert_record('log_display', $new_log_display);
+        $result = $result && $DB->insert_record('log_display', $new_log_display);
         
         $new_log_display = clone($new_log_display);
         $new_log_display->action = 'view';
-        $result = $result && insert_record('log_display', $new_log_display);
+        $result = $result && $DB->insert_record('log_display', $new_log_display);
         
         $new_log_display = clone($new_log_display);
         $new_log_display->action = 'view all';
         $new_log_display->mtable = 'course';
         $new_log_display->field = 'shortname';
-        $result = $result && insert_record('log_display', $new_log_display);
+        $result = $result && $DB->insert_record('log_display', $new_log_display);
     }
 
     if ($result && $oldversion < 2008042900) {
@@ -205,7 +208,7 @@
         $field = new XMLDBField('autonumbering');
         $field->setAttributes(XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '1', 'multiple_submit');
         /// Launch add field2
-        $result = $result && add_field($table, $field);
+        $result = $result && $dbman->add_field($table, $field);
     }
 
     if ($result && $oldversion < 2008050104) {
@@ -214,7 +217,7 @@
         $field = new XMLDBField('site_after_submit');
         $field->setAttributes(XMLDB_TYPE_CHAR, '255', null, null, false, null, null, '', 'autonumbering');
         /// Launch add field2
-        $result = $result && add_field($table, $field);
+        $result = $result && $dbman->add_field($table, $field);
     }
     return $result;
 }
Index: admin/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php,v
retrieving revision 1.8
diff -u -r1.8 new_table_from_mysql.class.php
--- admin/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php	10 Oct 2007 05:25:25 -0000	1.8
+++ admin/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php	15 May 2008 21:10:34 -0000
@@ -60,7 +60,7 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB, $db;
+        global $CFG, $XMLDB, $DB;
 
     /// Do the job, setting result as needed
     /// Get the dir containing the file
@@ -85,10 +85,9 @@
         /// No postaction here
             $this->postaction = NULL;
         /// Get list of tables
-            $dbtables = $db->MetaTables('TABLES');
+            $dbtables = $DB->get_tables();
             $selecttables = array();
             foreach ($dbtables as $dbtable) {
-                $dbtable = strtolower(str_replace($CFG->prefix, '', $dbtable));
                 $i = $structure->findTableInArray($dbtable);
                 if ($i === NULL) {
                     $selecttables[$dbtable] = $dbtable;
@@ -132,14 +131,11 @@
             $table = new XMLDBTable(strtolower(trim($tableparam)));
             $table->setComment($table->getName() . ' table retrofitted from MySQL');
         /// Get fields info from ADODb
-            if(!$dbfields = $db->MetaColumns($CFG->prefix . $tableparam)) {
-            ///Try it without prefix if doesn't exist
-                $dbfields = $db->MetaColumns($tableparam);
-            }
+            $dbfields = $DB->get_columns($tableparam);
             if ($dbfields) {
                 foreach ($dbfields as $dbfield) {
                 /// Create new XMLDB field
-                    $field = new XMLDBField(strtolower($dbfield->name));
+                    $field = new XMLDBField($dbfield->name);
                 /// Set field with info retrofitted
                     $field->setFromADOField($dbfield);
                 /// Add field to the table
@@ -147,7 +143,7 @@
                 }
             }
         /// Get PK, UK and indexes info from ADODb
-            $dbindexes = $db->MetaIndexes($CFG->prefix . $tableparam, true);
+            $dbindexes = $DB->get_indexes($tableparam);
             if ($dbindexes) {
                 $lastkey = NULL; //To temp store the last key processed
                 foreach ($dbindexes as $indexname => $dbindex) {
Index: help.php
===================================================================
RCS file: /cvsroot/moodle/moodle/help.php,v
retrieving revision 1.48
diff -u -r1.48 help.php
--- help.php	1 May 2008 02:46:09 -0000	1.48
+++ help.php	15 May 2008 21:10:26 -0000
@@ -193,9 +193,9 @@
 // Some functions for handling special cases ========================================
 
 function include_help_for_each_module($file, $langs, $helpdir) {
-    global $CFG;
+    global $CFG, $DB;
 
-    if (!$modules = get_records('modules', 'visible', 1)) {
+    if (!$modules = $DB->get_records('modules', array('visible'=>1))) {
         print_error('nomodules', 'debug');        // Should never happen
     }
     
Index: index.php
===================================================================
RCS file: /cvsroot/moodle/moodle/index.php,v
retrieving revision 1.209
diff -u -r1.209 index.php
--- index.php	30 Apr 2008 04:09:29 -0000	1.209
+++ index.php	15 May 2008 21:10:26 -0000
@@ -139,14 +139,14 @@
 /// Print Section
     if ($SITE->numsections > 0) {
 
-        if (!$section = get_record('course_sections', 'course', $SITE->id, 'section', 1)) {
+        if (!$section = $DB->get_record('course_sections', array('course'=>$SITE->id, 'section'=>1))) {
             delete_records('course_sections', 'course', $SITE->id, 'section', 1); // Just in case
             $section->course = $SITE->id;
             $section->section = 1;
             $section->summary = '';
             $section->sequence = '';
             $section->visible = 1;
-            $section->id = insert_record('course_sections', $section);
+            $section->id = $DB->insert_record('course_sections', $section);
         }
 
         if (!empty($section->sequence) or !empty($section->summary) or $editing) {
Index: file.php
===================================================================
RCS file: /cvsroot/moodle/moodle/file.php,v
retrieving revision 1.50
diff -u -r1.50 file.php
--- file.php	30 Apr 2008 04:09:29 -0000	1.50
+++ file.php	15 May 2008 21:10:26 -0000
@@ -42,7 +42,7 @@
     }
   
     // security: limit access to existing course subdirectories
-    if (($args[0]!='blog') and (!$course = get_record_sql("SELECT * FROM {$CFG->prefix}course WHERE id='".(int)$args[0]."'"))) {
+    if (($args[0]!='blog') and (!$course = $DB->get_record_sql("SELECT * FROM {course} WHERE id=?", array((int)$args[0])))) {
         print_error('invalidcourseid');
     }
 
@@ -140,18 +140,18 @@
         array_shift($rargs);
         $reference = implode('/', $rargs);
 
-        $sql = "SELECT COUNT(r.id) " .
-                 "FROM {$CFG->prefix}resource r, " .
-                      "{$CFG->prefix}course_modules cm, " .
-                      "{$CFG->prefix}modules m " .
-                 "WHERE r.course    = '{$course->id}' " .
-                   "AND m.name      = 'resource' " .
-                   "AND cm.module   = m.id " .
-                   "AND cm.instance = r.id " .
-                   "AND cm.visible  = 0 " .
-                   "AND r.type      = 'file' " .
-                   "AND r.reference = '{$reference}'";
-        if (count_records_sql($sql)) {
+        $sql = "SELECT COUNT(r.id)
+                  FROM {resource} r, {course_modules} cm, {modules} m
+                 WHERE r.course        = ?
+                       AND m.name      = 'resource'
+                       AND cm.module   = m.id
+                       AND cm.instance = r.id
+                       AND cm.visible  = 0
+                       AND r.type      = 'file'
+                       AND r.reference = ?";
+        $params = array($course->id, $reference);
+
+        if ($DB->count_records_sql($sql, $params)) {
            print_error('nopermissions');
         }
     }
Index: lib/db/upgradelib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/db/upgradelib.php,v
retrieving revision 1.15
diff -u -r1.15 upgradelib.php
--- lib/db/upgradelib.php	1 May 2008 20:29:04 -0000	1.15
+++ lib/db/upgradelib.php	15 May 2008 21:11:21 -0000
@@ -8,42 +8,43 @@
  */
 
 function upgrade_fix_category_depths() {
-    global $CFG, $db;
+    global $CFG, $DB;
 
     // first fix incorrect parents
     $sql = "SELECT c.id
-              FROM {$CFG->prefix}course_categories c
-             WHERE c.parent > 0 AND c.parent NOT IN (SELECT pc.id FROM {$CFG->prefix}course_categories pc)";
-    if ($rs = get_recordset_sql($sql)) {
-        while ($cat = rs_fetch_next_record($rs)) {
+              FROM {course_categories} c
+             WHERE c.parent > 0 AND c.parent NOT IN (SELECT pc.id FROM {course_categories} pc)";
+    if ($rs = $DB->get_recordset_sql($sql)) {
+        foreach ($rs as $cat) {
             $cat->depth  = 1;
             $cat->path   = '/'.$cat->id;
             $cat->parent = 0;
-            update_record('course_categories', $cat);
+            $DB->update_record('course_categories', $cat);
         }
-        rs_close($rs);
+        $rs->close();
     }
 
     // now add path and depth to top level categories
-    $sql = "UPDATE {$CFG->prefix}course_categories
+    $sql = "UPDATE {course_categories}
                SET depth = 1, path = ".sql_concat("'/'", "id")."
              WHERE parent = 0";
-    execute_sql($sql);
+    $DB->execute($sql);
 
     // now fix all other levels - slow but works in all supported dbs
     $parentdepth = 1;
-    $db->debug = true;
-    while (record_exists('course_categories', 'depth', 0)) {
+    while ($DB->record_exists('course_categories', array('depth'=>0))) {
         $sql = "SELECT c.id, pc.path
-                  FROM {$CFG->prefix}course_categories c, {$CFG->prefix}course_categories pc
-                 WHERE c.parent=pc.id AND c.depth=0 AND pc.depth=$parentdepth";
-        if ($rs = get_recordset_sql($sql)) {
-            while ($cat = rs_fetch_next_record($rs)) {
+                  FROM {course_categories} c, {course_categories} pc
+                 WHERE c.parent=pc.id AND c.depth=0 AND pc.depth=?";
+        if ($rs = $DB->get_recordset_sql($sql, array($parentdepth))) {
+            $DB->set_debug(false);
+            foreach ($rs as $cat) {
                 $cat->depth = $parentdepth+1;
                 $cat->path  = $cat->path.'/'.$cat->id;
-                update_record('course_categories', $cat);
+                $DB->update_record('course_categories', $cat);
             }
-            rs_close($rs);
+            $rs->close();
+            $DB->set_debug(false);
         }
         $parentdepth++;
         if ($parentdepth > 100) {
@@ -52,7 +53,6 @@
             break;
         }
     }
-    $db->debug = true;
 }
 
 ?>
Index: lib/db/install.xml
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/db/install.xml,v
retrieving revision 1.148
diff -u -r1.148 install.xml
--- lib/db/install.xml	12 May 2008 14:38:45 -0000	1.148
+++ lib/db/install.xml	15 May 2008 21:11:21 -0000
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="lib/db" VERSION="20080307" COMMENT="XMLDB file for core Moodle tables"
+<XMLDB PATH="lib/db" VERSION="20080514" COMMENT="XMLDB file for core Moodle tables"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
 >
@@ -377,7 +377,7 @@
         <INDEX NAME="name" UNIQUE="false" FIELDS="name"/>
       </INDEXES>
     </TABLE>
-    <TABLE NAME="sessions2" COMMENT="Optional database session storage in new format, not used by default" PREVIOUS="modules" NEXT="adodb_logsql">
+    <TABLE NAME="sessions2" COMMENT="Optional database session storage in new format, not used by default" PREVIOUS="modules" NEXT="timezone">
       <FIELDS>
         <FIELD NAME="sesskey" TYPE="char" LENGTH="64" NOTNULL="true" SEQUENCE="false" ENUM="false" NEXT="expiry"/>
         <FIELD NAME="expiry" TYPE="datetime" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="sesskey" NEXT="expireref"/>
@@ -394,21 +394,7 @@
         <INDEX NAME="expireref" UNIQUE="false" FIELDS="expireref" PREVIOUS="expiry"/>
       </INDEXES>
     </TABLE>
-    <TABLE NAME="adodb_logsql" COMMENT="to save some logs from ADOdb" PREVIOUS="sessions2" NEXT="timezone">
-      <FIELDS>
-        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" ENUM="false" NEXT="created"/>
-        <FIELD NAME="created" TYPE="datetime" LENGTH="2" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="id" NEXT="sql0"/>
-        <FIELD NAME="sql0" TYPE="char" LENGTH="250" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="created" NEXT="sql1"/>
-        <FIELD NAME="sql1" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" ENUM="false" PREVIOUS="sql0" NEXT="params"/>
-        <FIELD NAME="params" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" ENUM="false" PREVIOUS="sql1" NEXT="tracer"/>
-        <FIELD NAME="tracer" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" ENUM="false" PREVIOUS="params" NEXT="timer"/>
-        <FIELD NAME="timer" TYPE="number" LENGTH="16" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" DECIMALS="6" PREVIOUS="tracer"/>
-      </FIELDS>
-      <KEYS>
-        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
-      </KEYS>
-    </TABLE>
-    <TABLE NAME="timezone" COMMENT="Rules for calculating local wall clock time for users" PREVIOUS="adodb_logsql" NEXT="user">
+    <TABLE NAME="timezone" COMMENT="Rules for calculating local wall clock time for users" PREVIOUS="sessions2" NEXT="user">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" ENUM="false" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="id" NEXT="year"/>
Index: lib/db/upgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/db/upgrade.php,v
retrieving revision 1.197
diff -u -r1.197 upgrade.php
--- lib/db/upgrade.php	15 May 2008 17:03:49 -0000	1.197
+++ lib/db/upgrade.php	15 May 2008 21:11:21 -0000
@@ -19,10 +19,12 @@
 
 function xmldb_main_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $USER, $db;
+    global $CFG, $THEME, $USER, $DB;
 
     $result = true;
 
+    $dbman = $DB->get_manager(); // loads XSMLDB classes too
+
     ////////////////////////////////////////
     ///upgrade supported only from 1.9.x ///
     ////////////////////////////////////////
@@ -35,7 +37,7 @@
         $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('contextid', 'lowerboundary'));
 
     /// Launch drop index contextid-lowerboundary
-        $result = $result && drop_index($table, $index);
+        $result = $result && $dbman->drop_index($table, $index);
 
     /// Define index contextid-lowerboundary-letter (unique) to be added to grade_letters
         $table = new XMLDBTable('grade_letters');
@@ -43,7 +45,7 @@
         $index->setAttributes(XMLDB_INDEX_UNIQUE, array('contextid', 'lowerboundary', 'letter'));
 
     /// Launch add index contextid-lowerboundary-letter
-        $result = $result && add_index($table, $index);
+        $result = $result && $dbman->add_index($table, $index);
 
     /// Main savepoint reached
         upgrade_main_savepoint($result, 2008030700);
@@ -51,7 +53,7 @@
 
     if ($result && $oldversion < 2008050100) {
         // Update courses that used weekscss to weeks
-        $result = set_field('course', 'format', 'weeks', 'format', 'weekscss');
+        $result = $DB->set_field('course', 'format', 'weeks', 'format', 'weekscss');
         upgrade_main_savepoint($result, 2008050100);
     }
 
@@ -98,8 +100,8 @@
         $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('idnumber'));
 
     /// Launch drop index idnumber
-        if (index_exists($table, $index)) {
-            $result = $result && drop_index($table, $index);
+        if ($dbman->index_exists($table, $index)) {
+            $result = $result && $dbman->drop_index($table, $index);
         }
 
     /// Changing precision of field idnumber on table user to (255)
@@ -108,17 +110,23 @@
         $field->setAttributes(XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, null, null, 'password');
 
     /// Launch change of precision for field idnumber
-        $result = $result && change_field_precision($table, $field);
+        $result = $result && $dbman->change_field_precision($table, $field);
 
     /// Launch add index idnumber again
         $index = new XMLDBIndex('idnumber');
         $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('idnumber'));
-        $result = $result && add_index($table, $index);
+        $result = $result && $dbman->add_index($table, $index);
 
     /// Main savepoint reached
         upgrade_main_savepoint($result, 2008051201);
     }
 
+/*
+ * TODO:
+ *   drop adodb_logsql table and create a ner general sql log table
+ *
+ */
+
     return $result;
 }
 
Index: lib/datalib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/datalib.php,v
retrieving revision 1.464
diff -u -r1.464 datalib.php
--- lib/datalib.php	1 May 2008 06:07:24 -0000	1.464
+++ lib/datalib.php	15 May 2008 21:10:59 -0000
@@ -1865,7 +1865,7 @@
     // Note that this function intentionally does not follow the normal Moodle DB access idioms.
     // This is for a good reason: it is the most frequently used DB update function,
     // so it has been optimised for speed.
-    global $db, $CFG, $USER;
+    global $DB, $CFG, $USER;
 
     if ($cm === '' || is_null($cm)) { // postgres won't translate empty string to its default
         $cm = 0;
@@ -1908,33 +1908,30 @@
     }
     $url=addslashes($url);
 
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; $PERF->logwrites++;};
+    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->logwrites++;};
 
     if ($CFG->type = 'oci8po') {
-        if (empty($info)) {
+        if ($info == '') {
             $info = ' ';
         }
     }
-    $sql ='INSERT INTO '. $CFG->prefix .'log (time, userid, course, ip, module, cmid, action, url, info)
-        VALUES (' . "'$timenow', '$userid', '$courseid', '$REMOTE_ADDR', '$module', '$cm', '$action', '$url', '$info')";
-
-    $result = $db->Execute($sql);
+    $log = array('time'=>$timenow, 'userid'=>$userid, 'course'=>$courseid, 'ip'=>$REMOTE_ADDR, 'module'=>$module,
+                 'cmid'=>$cm, 'action'=>$action, 'url'=>$url, 'info'=>$info);
+    $result = $DB->insert_record_raw('log', $log, false);
 
     // MDL-11893, alert $CFG->supportemail if insert into log failed
-    if (!$result && $CFG->supportemail) {
+    if (!$result and $CFG->supportemail and empty($CFG->noemailever)) {
+        // email_to_user is not usable because email_to_user tries to write to the logs table,
+        // and this will get caught in an infinite loop, if disk is full
         $site = get_site();
         $subject = 'Insert into log failed at your moodle site '.$site->fullname;
         $message = "Insert into log table failed at ". date('l dS \of F Y h:i:s A') .".\n It is possible that your disk is full.\n\n";
-        $message .= "The failed SQL is:\n\n" . $sql;
+        $message .= "The failed query parameters are:\n\n" . var_export($log, true);
 
-        // email_to_user is not usable because email_to_user tries to write to the logs table,
-        // and this will get caught in an infinite loop, if disk is full
-        if (empty($CFG->noemailever)) {
-            $lasttime = get_config('admin', 'lastloginserterrormail');
-            if(empty($lasttime) || time() - $lasttime > 60*60*24) { // limit to 1 email per day
-                mail($CFG->supportemail, $subject, $message);
-                set_config('lastloginserterrormail', time(), 'admin');
-            }
+        $lasttime = get_config('admin', 'lastloginserterrormail');
+        if(empty($lasttime) || time() - $lasttime > 60*60*24) { // limit to 1 email per day
+            mail($CFG->supportemail, $subject, $message);
+            set_config('lastloginserterrormail', time(), 'admin');
         }
     }
 
@@ -1956,7 +1953,7 @@
  */
 function user_accesstime_log($courseid=0) {
 
-    global $USER, $CFG, $PERF, $db;
+    global $USER, $CFG, $DB;
 
     if (!isloggedin() or !empty($USER->realuser)) {
         // no access tracking
@@ -1973,18 +1970,14 @@
     if ($timenow - $USER->lastaccess > LASTACCESS_UPDATE_SECS) {
     /// Update $USER->lastaccess for next checks
         $USER->lastaccess = $timenow;
-        if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++;};
 
-        $remoteaddr = getremoteaddr();
-        if ($db->Execute("UPDATE {$CFG->prefix}user
-                             SET lastip = '$remoteaddr', lastaccess = $timenow
-                           WHERE id = $USER->id")) {
-        } else {
-            debugging('Error: Could not update global user lastaccess information');  // Don't throw an error
-        }
-    /// Remove this record from record cache since it will change
-        if (!empty($CFG->rcache)) {
-            rcache_unset('user', $USER->id);
+        $last = new object();
+        $last->id         = $USER->id;
+        $last->lastip     = getremoteaddr();
+        $last->lastaccess = $timenow;
+
+        if (!$DB->update_record_raw('user', $last)) {
+            debugging('Error: Could not update global user lastaccess information', DEBUG_ALL);  // Don't throw an error
         }
     }
 
@@ -1995,42 +1988,30 @@
 
 /// Store course lastaccess times for the current user
     if (empty($USER->currentcourseaccess[$courseid]) or ($timenow - $USER->currentcourseaccess[$courseid] > LASTACCESS_UPDATE_SECS)) {
-        if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
 
-        $exists = false; // To detect if the user_lastaccess record exists or no
-        if ($rs = $db->Execute("SELECT timeaccess
-                                  FROM {$CFG->prefix}user_lastaccess
-                                 WHERE userid = $USER->id AND courseid = $courseid")) {
-            if (!$rs->EOF) {
-                $exists = true;
-                $lastaccess = reset($rs->fields);
-                if ($timenow - $lastaccess <  LASTACCESS_UPDATE_SECS) {
-                /// no need to update now, it was updated recently in concurrent login ;-)
-                    $rs->Close();
-                    return;
-                }
-            }
-            $rs->Close();
-        }
+        $lastaccess = $DB->get_field('user_lastaccess', 'timeaccess', array('userid'=>$USER->id, 'courseid'=>$courseid));
 
-    /// Update course lastaccess for next checks
-        $USER->currentcourseaccess[$courseid] = $timenow;
-        if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
-
-        if ($exists) { // user_lastaccess record exists, update it
-            if ($db->Execute("UPDATE {$CFG->prefix}user_lastaccess
-                                 SET timeaccess = $timenow
-                               WHERE userid = $USER->id AND courseid = $courseid")) {
-            } else {
-                debugging('Error: Could not update course user lastacess information');  // Don't throw an error
+        if ($lastaccess === false) {
+            // Update course lastaccess for next checks
+            $USER->currentcourseaccess[$courseid] = $timenow;
+
+            $last = new object();
+            $last->userid     = $USER->id;
+            $last->courseid   = $courseid;
+            $last->timeaccess = $timenow;
+            if (!$DB->insert_record_raw('user_lastaccess', $last, false)) {
+                debugging('Error: Could not insert course user lastaccess information', DEBUG_ALL);  // Don't throw an error
             }
+            
+        } else if ($timenow - $lastaccess <  LASTACCESS_UPDATE_SECS) {
+            // no need to update now, it was updated recently in concurrent login ;-)
 
-        } else { // user lastaccess record doesn't exist, insert it
-            if ($db->Execute("INSERT INTO {$CFG->prefix}user_lastaccess
-                                     (userid, courseid, timeaccess)
-                              VALUES ($USER->id, $courseid, $timenow)")) {
-            } else {
-                debugging('Error: Could not insert course user lastaccess information');  // Don't throw an error
+        } else {
+            // Update course lastaccess for next checks
+            $USER->currentcourseaccess[$courseid] = $timenow;
+
+            if (!$DB->set_field('user_lastaccess', 'timeaccess', $timenow, array('userid'=>$USER->id, 'courseid'=>$courseid))) {
+                debugging('Error: Could not update course user lastacess information');  // Don't throw an error
             }
         }
     }
Index: lib/setup.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/setup.php,v
retrieving revision 1.232
diff -u -r1.232 setup.php
--- lib/setup.php	7 May 2008 04:40:18 -0000	1.232
+++ lib/setup.php	15 May 2008 21:11:10 -0000
@@ -5,7 +5,7 @@
  * Normally this is only called by the main config.php file
  * Normally this file does not need to be edited.
  * @author Martin Dougiamas
- * @version $Id: setup.php,v 1.232 2008/05/07 04:40:18 fmarier Exp $
+ * @version $Id: setup.php,v 1.231 2008/05/01 21:53:10 skodak Exp $
  * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  * @package moodlecore
  */
@@ -54,11 +54,16 @@
  */
 global $COURSE;
 /**
- * Definition of db type
+ * Legacy definition of db type TODO: remove in 2.0
  * @global object(db) $db
  */
 global $db;
 /**
+ * Database instances
+ * @global object(mdb) $DB
+ */
+global $DB;
+/**
  * $THEME is a global that defines the site theme.
  *
  * Items found in the theme record:
@@ -115,81 +120,16 @@
         exit;
     }
 
-/// Connect to the database using adodb
-
-/// Set $CFG->dbfamily global
-/// and configure some other specific variables for each db BEFORE attempting the connection
-    preconfigure_dbconnection();
-
-    require_once($CFG->libdir .'/adodb/adodb.inc.php'); // Database access functions
-
-    $db = &ADONewConnection($CFG->dbtype);
-
-    // See MDL-6760 for why this is necessary. In Moodle 1.8, once we start using NULLs properly,
-    // we probably want to change this value to ''.
-    $db->null2null = 'A long random string that will never, ever match something we want to insert into the database, I hope. \'';
-
-    error_reporting(0);  // Hide errors
-
-    if (!isset($CFG->dbpersist) or !empty($CFG->dbpersist)) {    // Use persistent connection (default)
-        $dbconnected = $db->PConnect($CFG->dbhost,$CFG->dbuser,$CFG->dbpass,$CFG->dbname);
-    } else {                                                     // Use single connection
-        $dbconnected = $db->Connect($CFG->dbhost,$CFG->dbuser,$CFG->dbpass,$CFG->dbname);
-    }
-    if (! $dbconnected) {
-        // In the name of protocol correctness, monitoring and performance
-        // profiling, set the appropriate error headers for machine comsumption
-        if (isset($_SERVER['SERVER_PROTOCOL'])) { 
-            // Avoid it with cron.php. Note that we assume it's HTTP/1.x
-            header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');        
-        }
-        // and then for human consumption...
-        echo '<html><body>';
-        echo '<table align="center"><tr>';
-        echo '<td style="color:#990000; text-align:center; font-size:large; border-width:1px; '.
-             '    border-color:#000000; border-style:solid; border-radius: 20px; border-collapse: collapse; '.
-             '    -moz-border-radius: 20px; padding: 15px">';
-        echo '<p>Error: Database connection failed.</p>';
-        echo '<p>It is possible that the database is overloaded or otherwise not running properly.</p>';
-        echo '<p>The site administrator should also check that the database details have been correctly specified in config.php</p>';
-        echo '</td></tr></table>';
-        echo '</body></html>';
-
-        error_log('ADODB Error: '.$db->ErrorMsg()); // see MDL-14628
-
-        if (empty($CFG->noemailever) and !empty($CFG->emailconnectionerrorsto)) {
-            mail($CFG->emailconnectionerrorsto, 
-                 'WARNING: Database connection error: '.$CFG->wwwroot, 
-                 'Connection error: '.$CFG->wwwroot);
-        }
-        die;
-    }
-
-/// Forcing ASSOC mode for ADOdb (some DBs default to FETCH_BOTH)
-    $db->SetFetchMode(ADODB_FETCH_ASSOC);
-
-/// Starting here we have a correct DB conection but me must avoid
-/// to execute any DB transaction until "set names" has been executed
-/// some lines below!
-
-    error_reporting(E_ALL);       // Show errors from now on.
-
-    if (!isset($CFG->prefix)) {   // Just in case it isn't defined in config.php
-        $CFG->prefix = '';
-    }
-
-
 /// Define admin directory
-
     if (!isset($CFG->admin)) {   // Just in case it isn't defined in config.php
         $CFG->admin = 'admin';   // This is relative to the wwwroot and dirroot
     }
 
-/// Increase memory limits if possible
-    raise_memory_limit('96M');    // We should never NEED this much but just in case...
+    if (!isset($CFG->prefix)) {   // Just in case it isn't defined in config.php
+        $CFG->prefix = '';
+    }
 
 /// Load up standard libraries
-
     require_once($CFG->libdir .'/textlib.class.php');   // Functions to handle multibyte strings
     require_once($CFG->libdir .'/weblib.php');          // Functions for producing HTML
     require_once($CFG->libdir .'/dmllib.php');          // Functions to handle DB data (DML)
@@ -204,6 +144,12 @@
     //the problem is that we need specific version of quickforms and hacked excel files :-(
     ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path'));
 
+/// Connect to the database
+    setup_DB();
+
+/// Increase memory limits if possible
+    raise_memory_limit('96M');    // We should never NEED this much but just in case...
+
 /// Disable errors for now - needed for installation when debug enabled in config.php
     if (isset($CFG->debug)) {
         $originalconfigdebug = $CFG->debug;
@@ -212,16 +158,12 @@
         $originalconfigdebug = -1;
     }
 
-/// Set the client/server and connection to utf8
-/// and configure some other specific variables for each db
-    configure_dbconnection();
-
 /// Load up any configuration from the config table
     $CFG = get_config();
 
 /// Turn on SQL logging if required
     if (!empty($CFG->logsql)) {
-        $db->LogSQL();
+        $DB->set_logging(true);
     }
 
 /// Prevent warnings from roles when upgrading with debug on
@@ -671,7 +613,7 @@
                                              $USER->lastname);
         }
         if (isset($USER->realuser)) {
-            if ($realuser = get_record('user', 'id', $USER->realuser)) {
+            if ($realuser = $DB->get_record('user', array('id'=>$USER->realuser))) {
                 $apachelog_username = clean_filename($realuser->username." as ".$apachelog_username);
                 $apachelog_name = clean_filename($realuser->firstname." ".$realuser->lastname ." as ".$apachelog_name);
                 $apachelog_userid = clean_filename($realuser->id." as ".$apachelog_userid);
Index: lib/environmentlib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/environmentlib.php,v
retrieving revision 1.28
diff -u -r1.28 environmentlib.php
--- lib/environmentlib.php	8 Nov 2007 05:13:18 -0000	1.28
+++ lib/environmentlib.php	15 May 2008 21:11:00 -0000
@@ -680,7 +680,7 @@
  * @return object results encapsulated in one environment_result object
  */
 function environment_check_unicode($version) {
-    global $db;
+    global $db, $DB;
 
     $result = new environment_results('unicode');
 
@@ -704,7 +704,7 @@
         $level = get_level($data['#']['UNICODE']['0']);
     }
 
-    if (!$unicodedb = setup_is_unicodedb()) {
+    if (!$unicodedb = $DB->setup_is_unicodedb()) {
         $result->setStatus(false);
     } else {
         $result->setStatus(true);
@@ -725,7 +725,7 @@
  */
 function environment_check_database($version) {
 
-    global $db;
+    global $DB;
 
     $result = new environment_results('database');
 
@@ -779,9 +779,9 @@
     }
 
 /// Now search the version we are using (depending of vendor)
-    $current_vendor = set_dbfamily();
+    $current_vendor = $DB->get_dbfamily();
 
-    $dbinfo = $db->ServerInfo();
+    $dbinfo = $DB->get_server_info();
     $current_version = normalize_version($dbinfo['version']);
     $needed_version = $vendors[$current_vendor];
 
Index: lib/locallib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/locallib.php,v
retrieving revision 1.15
diff -u -r1.15 locallib.php
--- lib/locallib.php	4 Apr 2008 02:54:32 -0000	1.15
+++ lib/locallib.php	15 May 2008 21:11:03 -0000
@@ -141,11 +141,11 @@
         require_once ($CFG->dirroot .'/local/db/upgrade.php');
 
         if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-        $db->debug=true;
+            $DB->set_debug(true);
         }
         if (xmldb_local_upgrade($CFG->local_version)) {
             if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-            $db->debug=false;
+                $DB->set_debug(false);
             }
             if (set_config('local_version', $local_version)) {
                 notify(get_string('databasesuccess'), 'notifysuccess');
@@ -167,7 +167,7 @@
             }
         } else {
             if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-            $db->debug=false;
+                $DB->set_debug(false);
             }
             print_error('Upgrade failed!  See local/version.php');
         }
Index: lib/dmllib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/dmllib.php,v
retrieving revision 1.146
diff -u -r1.146 dmllib.php
--- lib/dmllib.php	7 May 2008 13:04:43 -0000	1.146
+++ lib/dmllib.php	15 May 2008 21:11:00 -0000
@@ -1,4 +1,4 @@
-<?php // $Id: dmllib.php,v 1.146 2008/05/07 13:04:43 tjhunt Exp $
+<?php // $Id: dmllib.php,v 1.145 2008/04/20 21:19:38 stronk7 Exp $
 
 ///////////////////////////////////////////////////////////////////////////
 //                                                                       //
@@ -37,2734 +37,426 @@
 
 /// GLOBAL CONSTANTS /////////////////////////////////////////////////////////
 
-$empty_rs_cache = array();   // Keeps copies of the recordsets used in one invocation
-$metadata_cache = array();   // Kereeps copies of the MetaColumns() for each table used in one invocations
+require_once($CFG->libdir.'/dmllib_todo.php');
 
-$rcache = new StdClass;      // Cache simple get_record results
-$rcache->data   = array();
-$rcache->hits   = 0;
-$rcache->misses = 0;
+/**
+ * Bitmask, indicates only :name type parameters are supported by db backend.
+ */
+define('SQL_PARAMS_NAMED', 1);
 
-/// FUNCTIONS FOR DATABASE HANDLING  ////////////////////////////////
+/**
+ * Bitmask, indicates only ? type parameters are supported by db backend.
+ */
+define('SQL_PARAMS_QM', 2);
 
 /**
- * Execute a given sql command string
- *
- * Completely general function - it just runs some SQL and reports success.
- *
- * @uses $db
- * @param string $command The sql string you wish to be executed.
- * @param bool $feedback Set this argument to true if the results generated should be printed. Default is true.
- * @return bool success
+ * Bitmask, indicates only $1, $2.. type parameters are supported by db backend.
  */
-function execute_sql($command, $feedback=true) {
-/// Completely general function - it just runs some SQL and reports success.
+define('SQL_PARAMS_DOLAR', 4);
 
-    global $db, $CFG;
 
-    $olddebug = $db->debug;
+/**
+ * Sets up global $DB moodle_database instance
+ * @return void
+ */
+function setup_DB() {
+    global $CFG, $DB;
 
-    if (!$feedback) {
-        if ( !defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-        $db->debug = false;
+    if (isset($DB)) {
+        return;
     }
+
+    if (!isset($CFG->dbuser)) {
+        $CFG->dbuser = '';
     }
 
-    if ($CFG->version >= 2006101007) { //Look for trailing ; from Moodle 1.7.0
-        $command = trim($command);
-    /// If the trailing ; is there, fix and warn!
-        if (substr($command, strlen($command)-1, 1) == ';') {
-        /// One noticeable exception, Oracle PL/SQL blocks require ending in ";"
-            if ($CFG->dbfamily == 'oracle' && substr($command, -4) == 'END;') {
-                /// Nothing to fix/warn. The command is one PL/SQL block, so it's ok.
-            } else {
-                $command = trim($command, ';');
-                debugging('Warning. Avoid to end your SQL commands with a trailing ";".', DEBUG_DEVELOPER);
-            }
-        }
+    if (!isset($CFG->dbpass)) {
+        $CFG->dbpass = '';
     }
 
-    $empty_rs_cache = array();  // Clear out the cache, just in case changes were made to table structures
+    if (!isset($CFG->dbname)) {
+        $CFG->dbname = '';
+    }
 
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+    if (!isset($CFG->dbpersist)) {
+        $CFG->dbpersist = false;
+    }
 
-    $rs = $db->Execute($command);
+    if (!isset($CFG->dblibrary)) {
+        $CFG->dblibrary = 'adodb';
+    }
 
-    $db->debug = $olddebug;
+    if ($CFG->dblibrary == 'adodb') {
+        $classname = $CFG->dbtype.'_adodb_moodle_database';
+        require_once($CFG->libdir.'/dml/'.$classname.'.php');
+        $DB = new $classname($CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->dbpersist, $CFG->prefix);
 
-    if ($rs) {
-        if ($feedback) {
-            notify(get_string('success'), 'notifysuccess');
-        }
-        return true;
     } else {
-        if ($feedback) {
-            if ( defined('CLI_UPGRADE') && CLI_UPGRADE ) {
-                notify (get_string('error'));
-            } else {
-            notify('<strong>' . get_string('error') . '</strong>');
-            }
-        }
-        // these two may go to difference places
-        debugging($db->ErrorMsg() .'<br /><br />'. s($command));
-        if (!empty($CFG->dblogerror)) {
-            $debug=array_shift(debug_backtrace());
-            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $command");
-        }
-        return false;
+        error('Not implemented db library yet: '.$CFG->dblibrary);
     }
-}
-
-/**
-* on DBs that support it, switch to transaction mode and begin a transaction
-* you'll need to ensure you call commit_sql() or your changes *will* be lost.
-*
-* Now using ADOdb standard transactions. Some day, we should switch to
-* Smart Transactions (http://phplens.com/adodb/tutorial.smart.transactions.html)
-* as they autodetect errors and are nestable and easier to write
-*
-* this is _very_ useful for massive updates
-*/
-function begin_sql() {
-
-    global $db;
-
-    $db->BeginTrans();
-
-    return true;
-}
-
-/**
-* on DBs that support it, commit the transaction
-*
-* Now using ADOdb standard transactions. Some day, we should switch to
-* Smart Transactions (http://phplens.com/adodb/tutorial.smart.transactions.html)
-* as they autodetect errors and are nestable and easier to write
-*/
-function commit_sql() {
 
-    global $db;
+    $CFG->dbfamily = $DB->get_dbfamily(); // TODO: BC only for now
 
-    $db->CommitTrans();
-
-    return true;
-}
-
-/**
-* on DBs that support it, rollback the transaction
-*
-* Now using ADOdb standard transactions. Some day, we should switch to
-* Smart Transactions (http://phplens.com/adodb/tutorial.smart.transactions.html)
-* as they autodetect errors and are nestable and easier to write
-*/
-function rollback_sql() {
-
-    global $db;
+    $prevdebug = error_reporting(E_ALL);  // do not hide errors yet
+    if (!$DB->connect()) {
+        // In the name of protocol correctness, monitoring and performance
+        // profiling, set the appropriate error headers for machine comsumption
+        if (isset($_SERVER['SERVER_PROTOCOL'])) {
+            // Avoid it with cron.php. Note that we assume it's HTTP/1.x
+            header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
+        }
+        // and then for human consumption...
+        echo '<html><body>';
+        echo '<table align="center"><tr>';
+        echo '<td style="color:#990000; text-align:center; font-size:large; border-width:1px; '.
+             '    border-color:#000000; border-style:solid; border-radius: 20px; border-collapse: collapse; '.
+             '    -moz-border-radius: 20px; padding: 15px">';
+        echo '<p>Error: Database connection failed.</p>';
+        echo '<p>It is possible that the database is overloaded or otherwise not running properly.</p>';
+        echo '<p>The site administrator should also check that the database details have been correctly specified in config.php</p>';
+        echo '</td></tr></table>';
+        echo '</body></html>';
 
-    $db->RollbackTrans();
+        if (empty($CFG->noemailever) and !empty($CFG->emailconnectionerrorsto)) {
+            mail($CFG->emailconnectionerrorsto,
+                 'WARNING: Database connection error: '.$CFG->wwwroot,
+                 'Connection error: '.$CFG->wwwroot);
+        }
+        die;
+    }
+    error_reporting($prevdebug);
 
     return true;
 }
 
 /**
- * returns db specific uppercase function
- * @deprecated Moodle 1.7 because all the RDBMS use upper()
- */
-function db_uppercase() {
-    return "upper";
-}
-
-/**
- * returns db specific lowercase function
- * @deprecated Moodle 1.7 because all the RDBMS use lower()
+ * Interface definitions for resultsets returned from database functions.
+ * This is a simple Iterator with needed recorset closing support.
+ *
+ * The differnece from old recorset is that the records are returned
+ * as objects, not arrays. You should use "foreach ($recordset as $record) {}".
+ *
+ * Do not forget to close all recordsets when they are not needed anymore!
  */
-function db_lowercase() {
-    return "lower";
+interface moodle_recordset extends Iterator {
+    /**
+     * Free resources and connections, recordset can not be used anymore.
+     */
+    public function close();
 }
 
-
 /**
- * Run an arbitrary sequence of semicolon-delimited SQL commands
- *
- * Assumes that the input text (file or string) consists of
- * a number of SQL statements ENDING WITH SEMICOLONS.  The
- * semicolons MUST be the last character in a line.
- * Lines that are blank or that start with "#" or "--" (postgres) are ignored.
- * Only tested with mysql dump files (mysqldump -p -d moodle)
- *
- * @uses $CFG
- *
- * @deprecated Moodle 1.7 use the new XMLDB stuff in lib/ddllib.php
- *
- * @param string $sqlfile The path where a file with sql commands can be found on the server.
- * @param string $sqlstring If no path is supplied then a string with semicolon delimited sql
- * commands can be supplied in this argument.
- * @return bool Returns true if databse was modified successfully.
+ * Detail database field information.
+ * Based on ADOFieldObject.
  */
-function modify_database($sqlfile='', $sqlstring='') {
-
-    global $CFG;
-
-    if ($CFG->version > 2006101007) {
-        debugging('Function modify_database() is deprecated. Replace it with the new XMLDB stuff.', DEBUG_DEVELOPER);
-    }
-
-    $success = true;  // Let's be optimistic
-
-    if (!empty($sqlfile)) {
-        if (!is_readable($sqlfile)) {
-            $success = false;
-            echo '<p>Tried to modify database, but "'. $sqlfile .'" doesn\'t exist!</p>';
-            return $success;
-        } else {
-            $lines = file($sqlfile);
-        }
-    } else {
-        $sqlstring = trim($sqlstring);
-        if ($sqlstring{strlen($sqlstring)-1} != ";") {
-            $sqlstring .= ";"; // add it in if it's not there.
-        }
-        $lines[] = $sqlstring;
-    }
+class database_column_info {
+    public $name;
+    public $type;         // raw db field type
+    public $max_length;
+    public $scale;
+    public $enums;
+    public $not_null;
+    public $primary_key;
+    public $auto_increment;
+    public $binary;
+    public $unsigned;
+    public $zerofill;
+    public $has_default;
+    public $default_value;
+    public $unique;
 
-    $command = '';
+    public $meta_type; // type as one character
 
-    foreach ($lines as $line) {
-        $line = rtrim($line);
-        $length = strlen($line);
-
-        if ($length and $line[0] <> '#' and $line[0].$line[1] <> '--') {
-            if (substr($line, $length-1, 1) == ';') {
-                $line = substr($line, 0, $length-1);   // strip ;
-                $command .= $line;
-                $command = str_replace('prefix_', $CFG->prefix, $command); // Table prefixes
-                if (! execute_sql($command)) {
-                    $success = false;
-                }
-                $command = '';
-            } else {
-                $command .= $line;
+    /**
+     * Contructor
+     * @param $data mixed object or array with properties
+     */
+    public function database_column_info($data) {
+        foreach ($data as $key=>$value) {
+            if (array_key_exists($key, $this)) {
+                $this->$key = $value;
             }
         }
     }
-
-    return $success;
-
 }
 
-/// GENERIC FUNCTIONS TO CHECK AND COUNT RECORDS ////////////////////////////////////////
 
-/**
- * Test whether a record exists in a table where all the given fields match the given values.
- *
- * The record to test is specified by giving up to three fields that must
- * equal the corresponding values.
- *
- * @uses $CFG
- * @param string $table The table to check.
- * @param string $field1 the first field to check (optional).
- * @param string $value1 the value field1 must have (requred if field1 is given, else optional).
- * @param string $field2 the second field to check (optional).
- * @param string $value2 the value field2 must have (requred if field2 is given, else optional).
- * @param string $field3 the third field to check (optional).
- * @param string $value3 the value field3 must have (requred if field3 is given, else optional).
- * @return bool true if a matching record exists, else false.
- */
-function record_exists($table, $field1='', $value1='', $field2='', $value2='', $field3='', $value3='') {
 
-    global $CFG;
 
-    $select = where_clause($field1, $value1, $field2, $value2, $field3, $value3);
 
-    return record_exists_sql('SELECT * FROM '. $CFG->prefix . $table .' '. $select);
-}
 
-/**
- * Test whether any records exists in a table which match a particular WHERE clause.
- *
- * @uses $CFG
- * @param string $table The database table to be checked against.
- * @param string $select A fragment of SQL to be used in a WHERE clause in the SQL call.
- * @return bool true if a matching record exists, else false.
- */
-function record_exists_select($table, $select='') {
 
-    global $CFG;
 
-    if ($select) {
-        $select = 'WHERE '.$select;
-    }
 
-    return record_exists_sql('SELECT * FROM '. $CFG->prefix . $table . ' ' . $select);
-}
 
-/**
- * Test whether a SQL SELECT statement returns any records.
- *
- * This function returns true if the SQL statement executes
- * without any errors and returns at least one record.
- *
- * @param string $sql The SQL statement to execute.
- * @return bool true if the SQL executes without errors and returns at least one record.
- */
-function record_exists_sql($sql) {
 
-    $limitfrom = 0; /// Number of records to skip
-    $limitnum  = 1; /// Number of records to retrieve
 
-    if (!$rs = get_recordset_sql($sql, $limitfrom, $limitnum)) {
-        return false;
-    }
+/////// DEPRECATED - works fine
 
-    if (rs_EOF($rs)) {
-        $result = false;
-    } else {
-        $result = true;
-    }
 
-    rs_close($rs);
-    return $result;
+function sql_ilike() {
+    global $DB;
+    return $DB->sql_ilike();
 }
 
-/**
- * Count the records in a table where all the given fields match the given values.
- *
- * @uses $CFG
- * @param string $table The table to query.
- * @param string $field1 the first field to check (optional).
- * @param string $value1 the value field1 must have (requred if field1 is given, else optional).
- * @param string $field2 the second field to check (optional).
- * @param string $value2 the value field2 must have (requred if field2 is given, else optional).
- * @param string $field3 the third field to check (optional).
- * @param string $value3 the value field3 must have (requred if field3 is given, else optional).
- * @return int The count of records returned from the specified criteria.
- */
-function count_records($table, $field1='', $value1='', $field2='', $value2='', $field3='', $value3='') {
-
-    global $CFG;
+function sql_fullname($first='firstname', $last='lastname') {
+    global $DB;
+    return $DB->sql_fullname($first, $last);
+}
 
-    $select = where_clause($field1, $value1, $field2, $value2, $field3, $value3);
+function sql_concat() {
+    global $DB;
 
-    return count_records_sql('SELECT COUNT(*) FROM '. $CFG->prefix . $table .' '. $select);
+    $args = func_get_args();
+    return call_user_func_array(array($DB, 'sql_concat'), $args);
 }
 
-/**
- * Count the records in a table which match a particular WHERE clause.
- *
- * @uses $CFG
- * @param string $table The database table to be checked against.
- * @param string $select A fragment of SQL to be used in a WHERE clause in the SQL call.
- * @param string $countitem The count string to be used in the SQL call. Default is COUNT(*).
- * @return int The count of records returned from the specified criteria.
- */
-function count_records_select($table, $select='', $countitem='COUNT(*)') {
+function sql_empty() {
+    global $DB;
+    return $DB->sql_empty();
+}
 
-    global $CFG;
+function sql_substr() {
+    global $DB;
+    return $DB->sql_substr();
+}
 
-    if ($select) {
-        $select = 'WHERE '.$select;
-    }
+function sql_bitand($int1, $int2) {
+    global $DB;
+    return $DB->sql_bitand($int1, $int2);
+}
 
-    return count_records_sql('SELECT '. $countitem .' FROM '. $CFG->prefix . $table .' '. $select);
+function sql_bitnot($int1) {
+    global $DB;
+    return $DB->sql_bitnot($int1);
 }
 
-/**
- * Get the result of a SQL SELECT COUNT(...) query.
- *
- * Given a query that counts rows, return that count. (In fact,
- * given any query, return the first field of the first record
- * returned. However, this method should only be used for the
- * intended purpose.) If an error occurrs, 0 is returned.
- *
- * @uses $CFG
- * @uses $db
- * @param string $sql The SQL string you wish to be executed.
- * @return int the count. If an error occurrs, 0 is returned.
- */
-function count_records_sql($sql) {
-    $rs = get_recordset_sql($sql);
+function sql_bitor($int1, $int2) {
+    global $DB;
+    return $DB->sql_bitor($int1);
 
-    if (is_object($rs) and is_array($rs->fields)) {
-        return reset($rs->fields);
-    } else {
-        return 0;
-    }
 }
 
-/// GENERIC FUNCTIONS TO GET, INSERT, OR UPDATE DATA  ///////////////////////////////////
+function sql_bitxor($int1, $int2) {
+    global $DB;
+    return $DB->sql_bitxor($int1, $int2);
 
+}
 
-/**
- * Get a single record as an object
- *
- * @uses $CFG
- * @param string $table The table to select from.
- * @param string $field1 the first field to check (optional).
- * @param string $value1 the value field1 must have (requred if field1 is given, else optional).
- * @param string $field2 the second field to check (optional).
- * @param string $value2 the value field2 must have (requred if field2 is given, else optional).
- * @param string $field3 the third field to check (optional).
- * @param string $value3 the value field3 must have (requred if field3 is given, else optional).
- * @return mixed a fieldset object containing the first mathcing record, or false if none found.
- */
-function get_record($table, $field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields='*') {
+function sql_cast_char2int($fieldname, $text=false) {
+    global $DB;
+    return $DB->sql_cast_char2int($fieldname, $text);
+}
 
-    global $CFG;
+function sql_compare_text($fieldname, $numchars=32) {
+    return sql_order_by_text($fieldname, $numchars);
+}
+
+function sql_order_by_text($fieldname, $numchars=32) {
+    global $DB;
+    return $DB->sql_order_by_text($fieldname, $numchars);
+}
 
-    // Check to see whether this record is eligible for caching (fields=*, only condition is id)
-    $docache = false;
-    if (!empty($CFG->rcache) && $CFG->rcache === true && $field1=='id' && !$field2 && !$field3 && $fields=='*') {
-        $docache = true;
-        // If it's in the cache, return it
-        $cached = rcache_getforfill($table, $value1);
-        if (!empty($cached)) {
-            return $cached;
-        }
-    }
 
-    $select = where_clause($field1, $value1, $field2, $value2, $field3, $value3);
+function sql_concat_join($separator="' '", $elements=array()) {
+    global $DB;
+    return $DB->sql_concat_join($separator, $elements);
+}
 
-    $record = get_record_sql('SELECT '.$fields.' FROM '. $CFG->prefix . $table .' '. $select);
+function sql_isempty($tablename, $fieldname, $nullablefield, $textfield) {
+    global $DB;
+    return $DB->sql_isempty($tablename, $fieldname, $nullablefield, $textfield);
+}
 
-    // If we're caching records, store this one
-    // (supposing we got something - we don't cache failures)
-    if ($docache) {
-        if ($record !== false) {
-            rcache_set($table, $value1, $record);
-        } else {
-            rcache_releaseforfill($table, $value1);
-        }
-    }
-    return $record;
+function sql_isnotempty($tablename, $fieldname, $nullablefield, $textfield) {
+    global $DB;
+    return $DB->sql_isnotempty($tablename, $fieldname, $nullablefield, $textfield);
 }
 
-/**
- * Get a single record as an object using an SQL statement
- *
- * The SQL statement should normally only return one record. In debug mode
- * you will get a warning if more record is returned (unless you
- * set $expectmultiple to true). In non-debug mode, it just returns
- * the first record.
- *
- * @uses $CFG
- * @uses $db
- * @param string $sql The SQL string you wish to be executed, should normally only return one record.
- * @param bool $expectmultiple If the SQL cannot be written to conveniently return just one record,
- *      set this to true to hide the debug message.
- * @param bool $nolimit sometimes appending ' LIMIT 1' to the SQL causes an error. Set this to true
- *      to stop your SQL being modified. This argument should probably be deprecated.
- * @return Found record as object. False if not found or error
- */
-function get_record_sql($sql, $expectmultiple=false, $nolimit=false) {
 
-    global $CFG;
+function begin_sql() {
+    global $DB;
+    return $DB->begin_sql();
+}
 
-/// Default situation
-    $limitfrom = 0; /// Number of records to skip
-    $limitnum  = 1; /// Number of records to retrieve
-
-/// Only a few uses of the 2nd and 3rd parameter have been found
-/// I think that we should avoid to use them completely, one
-/// record is one record, and everything else should return error.
-/// So the proposal is to change all the uses, (4-5 inside Moodle
-/// Core), drop them from the definition and delete the next two
-/// "if" sentences. (eloy, 2006-08-19)
-
-    if ($nolimit) {
-        $limitfrom = 0;
-        $limitnum  = 0;
-    } else if ($expectmultiple) {
-        $limitfrom = 0;
-        $limitnum  = 1;
-    } else if (debugging('', DEBUG_DEVELOPER)) {
-        // Debugging mode - don't use a limit of 1, but do change the SQL, because sometimes that
-        // causes errors, and in non-debug mode you don't see the error message and it is
-        // impossible to know what's wrong.
-        $limitfrom = 0;
-        $limitnum  = 100;
-    }
-
-    if (!$rs = get_recordset_sql($sql, $limitfrom, $limitnum)) {
-        return false;
-    }
-
-    $recordcount = $rs->RecordCount();
-
-    if ($recordcount == 0) {          // Found no records
-        return false;
-
-    } else if ($recordcount == 1) {    // Found one record
-    /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
-    /// to '' (empty string) for Oracle. It's the only way to work with
-    /// all those NOT NULL DEFAULT '' fields until we definitively delete them
-        if ($CFG->dbfamily == 'oracle') {
-            array_walk($rs->fields, 'onespace2empty');
-        }
-    /// End of DIRTY HACK
-        return (object)$rs->fields;
+function commit_sql() {
+    global $DB;
+    return $DB->commit_sql();
+}
 
-    } else {                          // Error: found more than one record
-        notify('Error:  Turn off debugging to hide this error.');
-        notify($sql . '(with limits ' . $limitfrom . ', ' . $limitnum . ')');
-        if ($records = $rs->GetAssoc(true)) {
-            notify('Found more than one record in get_record_sql !');
-            print_object($records);
-        } else {
-            notify('Very strange error in get_record_sql !');
-            print_object($rs);
-        }
-        print_continue("$CFG->wwwroot/$CFG->admin/config.php");
-    }
+function rollback_sql() {
+    global $DB;
+    return $DB->rollback_sql();
 }
 
-/**
- * Gets one record from a table, as an object
- *
- * @uses $CFG
- * @param string $table The database table to be checked against.
- * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
- * @param string $fields A comma separated list of fields to be returned from the chosen table.
- * @return object|false Returns an array of found records (as objects) or false if no records or error occured.
- */
-function get_record_select($table, $select='', $fields='*') {
+function insert_record($table, $dataobject, $returnid=true, $primarykey='id') {
+    global $DB;
 
-    global $CFG;
+    $dataobject = stripslashes_recursive($dataobject);
+    return $DB->insert_record($table, $dataobject, $returnid);
+}
 
-    if ($select) {
-        $select = 'WHERE '. $select;
-    }
+function update_record($table, $dataobject) {
+    global $DB;
 
-    return get_record_sql('SELECT '. $fields .' FROM '. $CFG->prefix . $table .' '. $select);
+    $dataobject = stripslashes_recursive($dataobject);
+    return $DB->update_record($table, $dataobject, true);
 }
 
-/**
- * Get a number of records as an ADODB RecordSet.
- *
- * Selects records from the table $table.
- *
- * If specified, only records where the field $field has value $value are retured.
- *
- * If specified, the results will be sorted as specified by $sort. This
- * is added to the SQL as "ORDER BY $sort". Example values of $sort
- * mightbe "time ASC" or "time DESC".
- *
- * If $fields is specified, only those fields are returned.
- *
- * Since this method is a little less readable, use of it should be restricted to 
- * code where it's possible there might be large datasets being returned.  For known 
- * small datasets use get_records - it leads to simpler code.
- *
- * If you only want some of the records, specify $limitfrom and $limitnum.
- * The query will skip the first $limitfrom records (according to the sort
- * order) and then return the next $limitnum records. If either of $limitfrom
- * or $limitnum is specified, both must be present.
- *
- * The return value is an ADODB RecordSet object
- * @link http://phplens.com/adodb/reference.functions.adorecordset.html
- * if the query succeeds. If an error occurrs, false is returned.
- *
- * @param string $table the table to query.
- * @param string $field a field to check (optional).
- * @param string $value the value the field must have (requred if field1 is given, else optional).
- * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
- * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an ADODB RecordSet object, or false if an error occured.
- */
-function get_recordset($table, $field='', $value='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+function get_records($table, $field='', $value='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+    global $DB;
 
+    $conditions = array();
     if ($field) {
-        $select = "$field = '$value'";
-    } else {
-        $select = '';
+        $conditions[$field] = stripslashes_recursive($value);
     }
 
-    return get_recordset_select($table, $select, $sort, $fields, $limitfrom, $limitnum);
+    return $DB->get_records($table, $conditions, $sort, $fields, $limitfrom, $limitnum);
 }
 
-/**
- * Get a number of records as an ADODB RecordSet.
- *
- * If given, $select is used as the SELECT parameter in the SQL query,
- * otherwise all records from the table are returned.
- *
- * Other arguments and the return type as for @see function get_recordset.
- *
- * @uses $CFG
- * @param string $table the table to query.
- * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
- * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
- * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an ADODB RecordSet object, or false if an error occured.
- */
-function get_recordset_select($table, $select='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
-
-    global $CFG;
+function get_record($table, $field1, $value1, $field2='', $value2='', $field3='', $value3='', $fields='*') {
+    global $DB;
 
-    if ($select) {
-        $select = ' WHERE '. $select;
+    $conditions = array();
+    if ($field1) {
+        $conditions[$field1] = stripslashes_recursive($value1);
     }
-
-    if ($sort) {
-        $sort = ' ORDER BY '. $sort;
+    if ($field2) {
+        $conditions[$field2] = stripslashes_recursive($value2);
+    }
+    if ($field3) {
+        $conditions[$field3] = stripslashes_recursive($value3);
     }
 
-    return get_recordset_sql('SELECT '. $fields .' FROM '. $CFG->prefix . $table . $select . $sort, $limitfrom, $limitnum);
+    return $DB->get_record($table, $conditions, $fields);
 }
 
-/**
- * Get a number of records as an ADODB RecordSet.
- *
- * Only records where $field takes one of the values $values are returned.
- * $values should be a comma-separated list of values, for example "4,5,6,10"
- * or "'foo','bar','baz'".
- *
- * Other arguments and the return type as for @see function get_recordset.
- *
- * @param string $table the table to query.
- * @param string $field a field to check (optional).
- * @param string $values comma separated list of values the field must have (requred if field is given, else optional).
- * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
- * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an ADODB RecordSet object, or false if an error occured.
- */
-function get_recordset_list($table, $field='', $values='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+function set_field($table, $newfield, $newvalue, $field1, $value1, $field2='', $value2='', $field3='', $value3='') {
+    global $DB;
 
-    if ($field) {
-        $select = "$field IN ($values)";
-    } else {
-        $select = '';
+    $conditions = array();
+    if ($field1) {
+        $conditions[$field1] = stripslashes_recursive($value1);
+    }
+    if ($field2) {
+        $conditions[$field2] = stripslashes_recursive($value2);
+    }
+    if ($field3) {
+        $conditions[$field3] = stripslashes_recursive($value3);
     }
 
-    return get_recordset_select($table, $select, $sort, $fields, $limitfrom, $limitnum);
+    return $DB->set_field($table, $newfield, $newvalue, $conditions);
 }
 
-/**
- * Get a number of records as an ADODB RecordSet.  $sql must be a complete SQL query.
- * Since this method is a little less readable, use of it should be restricted to 
- * code where it's possible there might be large datasets being returned.  For known 
- * small datasets use get_records_sql - it leads to simpler code.
- *
- * The return type is as for @see function get_recordset.
- *
- * @uses $CFG
- * @uses $db
- * @param string $sql the SQL select query to execute.
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an ADODB RecordSet object, or false if an error occured.
- */
-function get_recordset_sql($sql, $limitfrom=null, $limitnum=null) {
-    global $CFG, $db;
+function count_records($table, $field1='', $value1='', $field2='', $value2='', $field3='', $value3='') {
+    global $DB;
 
-    if (empty($db)) {
-        return false;
+    $conditions = array();
+    if ($field1) {
+        $conditions[$field1] = stripslashes_recursive($value1);
     }
-
-/// Temporary hack as part of phasing out all access to obsolete user tables  XXX
-    if (!empty($CFG->rolesactive)) {
-        if (strpos($sql, ' '.$CFG->prefix.'user_students ') ||
-            strpos($sql, ' '.$CFG->prefix.'user_teachers ') ||
-            strpos($sql, ' '.$CFG->prefix.'user_coursecreators ') ||
-            strpos($sql, ' '.$CFG->prefix.'user_admins ')) {
-            if (debugging()) { var_dump(debug_backtrace()); }
-            print_error('This SQL relies on obsolete tables!  Your code must be fixed by a developer.');
-        }
+    if ($field2) {
+        $conditions[$field2] = stripslashes_recursive($value2);
+    }
+    if ($field3) {
+        $conditions[$field3] = stripslashes_recursive($value3);
     }
 
+    return $DB->count_records($table, $conditions);
+}
 
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+function record_exists($table, $field1='', $value1='', $field2='', $value2='', $field3='', $value3='') {
+    global $DB;
 
-    if ($limitfrom || $limitnum) {
-        ///Special case, 0 must be -1 for ADOdb
-        $limitfrom = empty($limitfrom) ? -1 : $limitfrom;
-        $limitnum  = empty($limitnum) ? -1 : $limitnum;
-        $rs = $db->SelectLimit($sql, $limitnum, $limitfrom);
-    } else {
-        $rs = $db->Execute($sql);
+    $conditions = array();
+    if ($field1) {
+        $conditions[$field1] = stripslashes_recursive($value1);
     }
-    if (!$rs) {
-        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
-        if (!empty($CFG->dblogerror)) {
-            $debug=array_shift(debug_backtrace());
-            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql with limits ($limitfrom, $limitnum)");
-        }
-        return false;
+    if ($field2) {
+        $conditions[$field2] = stripslashes_recursive($value2);
+    }
+    if ($field3) {
+        $conditions[$field3] = stripslashes_recursive($value3);
     }
 
-    return $rs;
+    return $DB->record_exists($table, $conditions);
 }
 
-/**
- * Utility function used by the following 4 methods. Note that for this to work, the first column
- * in the recordset must contain unique values, as it is used as the key to the associative array.
- *
- * @param object an ADODB RecordSet object.
- * @return mixed mixed an array of objects, or false if an error occured or the RecordSet was empty.
- */
-function recordset_to_array($rs) {
-    global $CFG;
-
-    $debugging = debugging('', DEBUG_DEVELOPER);
+function delete_records($table, $field1='', $value1='', $field2='', $value2='', $field3='', $value3='') {
+    global $DB;
 
-    if ($rs && !rs_EOF($rs)) {
-        $objects = array();
-    /// First of all, we are going to get the name of the first column
-    /// to introduce it back after transforming the recordset to assoc array
-    /// See http://docs.moodle.org/en/XMLDB_Problems, fetch mode problem.
-        $firstcolumn = $rs->FetchField(0);
-    /// Get the whole associative array
-        if ($records = $rs->GetAssoc(true)) {
-            foreach ($records as $key => $record) {
-            /// Really DIRTY HACK for Oracle, but it's the only way to make it work
-            /// until we got all those NOT NULL DEFAULT '' out from Moodle
-                if ($CFG->dbfamily == 'oracle') {
-                    array_walk($record, 'onespace2empty');
-                }
-            /// End of DIRTY HACK
-                $record[$firstcolumn->name] = $key;/// Re-add the assoc field
-                if ($debugging && array_key_exists($key, $objects)) {
-                    debugging("Did you remember to make the first column something unique in your call to get_records? Duplicate value '$key' found in column '".$firstcolumn->name."'.", DEBUG_DEVELOPER);
-                }
-                $objects[$key] = (object) $record; /// To object
-            }
-            return $objects;
-    /// Fallback in case we only have 1 field in the recordset. MDL-5877
-        } else if ($rs->_numOfFields == 1 && $records = $rs->GetRows()) {
-            foreach ($records as $key => $record) {
-            /// Really DIRTY HACK for Oracle, but it's the only way to make it work
-            /// until we got all those NOT NULL DEFAULT '' out from Moodle
-                if ($CFG->dbfamily == 'oracle') {
-                    array_walk($record, 'onespace2empty');
-                }
-            /// End of DIRTY HACK
-                if ($debugging && array_key_exists($record[$firstcolumn->name], $objects)) {
-                    debugging("Did you remember to make the first column something unique in your call to get_records? Duplicate value '".$record[$firstcolumn->name]."' found in column '".$firstcolumn->name."'.", DEBUG_DEVELOPER);
-                }
-                $objects[$record[$firstcolumn->name]] = (object) $record; /// The key is the first column value (like Assoc)
-            }
-            return $objects;
-        } else {
-            return false;
-        }
-    } else {
-        return false;
+    $conditions = array();
+    if ($field1) {
+        $conditions[$field1] = stripslashes_recursive($value1);
     }
+    if ($field2) {
+        $conditions[$field2] = stripslashes_recursive($value2);
+    }
+    if ($field3) {
+        $conditions[$field3] = stripslashes_recursive($value3);
+    }
+
+    return $DB->delete_records($table, $conditions);
 }
 
-/**
- * This function is used to get the current record from the recordset. It
- * doesn't advance the recordset position. You'll need to do that by
- * using the rs_next_record($recordset) function.
- * @param ADORecordSet the recordset to fetch current record from
- * @return ADOFetchObj the object containing the fetched information
- */
-function rs_fetch_record(&$rs) {
-    global $CFG;
+function get_field($table, $return, $field1, $value1, $field2='', $value2='', $field3='', $value3='') {
+    global $DB;
 
-    if (!$rs) {
-        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
-        return false;
+    $conditions = array();
+    if ($field1) {
+        $conditions[$field1] = stripslashes_recursive($value1);
     }
-
-    $rec = $rs->FetchObj(); //Retrieve record as object without advance the pointer
-
-    if ($rs->EOF) { //FetchObj requires manual checking of EOF to detect if it's the last record
-        $rec = false;
-    } else {
-    /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
-    /// to '' (empty string) for Oracle. It's the only way to work with
-    /// all those NOT NULL DEFAULT '' fields until we definetively delete them
-        if ($CFG->dbfamily == 'oracle') {
-            $recarr = (array)$rec; /// Cast to array
-            array_walk($recarr, 'onespace2empty');
-            $rec = (object)$recarr;/// Cast back to object
-        }
-    /// End DIRTY HACK
+    if ($field2) {
+        $conditions[$field2] = stripslashes_recursive($value2);
+    }
+    if ($field3) {
+        $conditions[$field3] = stripslashes_recursive($value3);
     }
 
-    return $rec;
+    return $DB->get_field($table, $return, $conditions);
 }
 
-/**
- * This function is used to advance the pointer of the recordset
- * to its next position/record.
- * @param ADORecordSet the recordset to be moved to the next record
- * @return boolean true if the movement was successful and false if not (end of recordset)
- */
-function rs_next_record(&$rs) {
-    if (!$rs) {
-        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
-        return false;
-    }
 
-    return $rs->MoveNext(); //Move the pointer to the next record
-}
 
-/**
- * This function is used to get the current record from the recordset. It
- * does advance the recordset position.
- * This is the prefered way to iterate over recordsets with code blocks like this:
- *
- * $rs = get_recordset('SELECT .....');
- * while ($rec = rs_fetch_next_record($rs)) {
- *     /// Perform actions with the $rec record here
- * }
- * rs_close($rs); /// Close the recordset if not used anymore. Saves memory (optional but recommended).
- *
- * @param ADORecordSet the recordset to fetch current record from
- * @return mixed ADOFetchObj the object containing the fetched information or boolean false if no record (end of recordset)
- */
-function rs_fetch_next_record(&$rs) {
 
-    global $CFG;
 
-    if (!$rs) {
-        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
-        return false;
-    }
 
-    $rec = false;
-    $recarr = $rs->FetchRow(); //Retrieve record as object without advance the pointer. It's quicker that FetchNextObj()
 
-    if ($recarr) {
-    /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
-    /// to '' (empty string) for Oracle. It's the only way to work with
-    /// all those NOT NULL DEFAULT '' fields until we definetively delete them
-        if ($CFG->dbfamily == 'oracle') {
-            array_walk($recarr, 'onespace2empty');
-        }
-    /// End DIRTY HACK
-    /// Cast array to object
-        $rec = (object)$recarr;
-    }
 
-    return $rec;
+///// DELETED - must not be used anymore
+
+function configure_dbconnection() {
+    error('configure_dbconnection() removed');
 }
 
-/**
- * Returns true if no more records found
- * @param ADORecordSet the recordset
- * @return bool
- */
-function rs_EOF($rs) {
-    if (!$rs) {
-        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
-        return true;
-    }
-    return $rs->EOF;
+function sql_max($field) {
+    error('sql_max() removed - use normal sql MAX() instead');
 }
 
-/**
- * This function closes the recordset, freeing all the memory and associated resources.
- * Note that, once closed, the recordset must not be used anymore along the request.
- * Saves memory (optional but recommended).
- * @param ADORecordSet the recordset to be closed
- * @return void
- */
-function rs_close(&$rs) {
-    if (!$rs) {
-        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
-        return;
-    }
+function sql_as() {
+    error('sql_as() removed - do not use AS for tables at all');
+}
 
-    $rs->Close();
+function sql_paging_limit($page, $recordsperpage) {
+    error('Function sql_paging_limit() is deprecated. Replace it with the correct use of limitfrom, limitnum parameters');
 }
 
-/**
- * This function is used to convert all the Oracle 1-space defaults to the empty string
- * like a really DIRTY HACK to allow it to work better until all those NOT NULL DEFAULT ''
- * fields will be out from Moodle.
- * @param string the string to be converted to '' (empty string) if it's ' ' (one space)
- * @param mixed the key of the array in case we are using this function from array_walk,
- *              defaults to null for other (direct) uses
- * @return boolean always true (the converted variable is returned by reference)
- */
-function onespace2empty(&$item, $key=null) {
-    $item = $item == ' ' ? '' : $item;
-    return true;
+function db_uppercase() {
+    error('upper() removed - use normal sql UPPER()');
 }
-///End DIRTY HACK
 
+function db_lowercase() {
+    error('upper() removed - use normal sql LOWER()');
+}
 
-/**
- * Get a number of records as an array of objects.
- *
- * If the query succeeds and returns at least one record, the
- * return value is an array of objects, one object for each
- * record found. The array key is the value from the first
- * column of the result set. The object associated with that key
- * has a member variable for each column of the results.
- *
- * @param string $table the table to query.
- * @param string $field a field to check (optional).
- * @param string $value the value the field must have (requred if field1 is given, else optional).
- * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
- * @param string $fields a comma separated list of fields to return (optional, by default
- *   all fields are returned). The first field will be used as key for the
- *   array so must be a unique field such as 'id'.
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an array of objects, or false if no records were found or an error occured.
- */
-function get_records($table, $field='', $value='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
-    $rs = get_recordset($table, $field, $value, $sort, $fields, $limitfrom, $limitnum);
-    return recordset_to_array($rs);
-}
-
-/**
- * Get a number of records as an array of objects.
- *
- * Return value as for @see function get_records.
- *
- * @param string $table the table to query.
- * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
- * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
- * @param string $fields a comma separated list of fields to return
- *   (optional, by default all fields are returned). The first field will be used as key for the
- *   array so must be a unique field such as 'id'.
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an array of objects, or false if no records were found or an error occured.
- */
-function get_records_select($table, $select='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
-    $rs = get_recordset_select($table, $select, $sort, $fields, $limitfrom, $limitnum);
-    return recordset_to_array($rs);
-}
-
-/**
- * Get a number of records as an array of objects.
- *
- * Return value as for @see function get_records.
- *
- * @param string $table The database table to be checked against.
- * @param string $field The field to search
- * @param string $values Comma separated list of possible value
- * @param string $sort Sort order (as valid SQL sort parameter)
- * @param string $fields A comma separated list of fields to be returned from the chosen table. If specified,
- *   the first field should be a unique one such as 'id' since it will be used as a key in the associative
- *   array.
- * @return mixed an array of objects, or false if no records were found or an error occured.
- */
-function get_records_list($table, $field='', $values='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
-    $rs = get_recordset_list($table, $field, $values, $sort, $fields, $limitfrom, $limitnum);
-    return recordset_to_array($rs);
-}
-
-/**
- * Get a number of records as an array of objects.
- *
- * Return value as for @see function get_records.
- *
- * @param string $sql the SQL select query to execute. The first column of this SELECT statement
- *   must be a unique value (usually the 'id' field), as it will be used as the key of the
- *   returned array.
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an array of objects, or false if no records were found or an error occured.
- */
-function get_records_sql($sql, $limitfrom='', $limitnum='') {
-    $rs = get_recordset_sql($sql, $limitfrom, $limitnum);
-    return recordset_to_array($rs);
-}
-
-/**
- * Utility function used by the following 3 methods.
- *
- * @param object an ADODB RecordSet object with two columns.
- * @return mixed an associative array, or false if an error occured or the RecordSet was empty.
- */
-function recordset_to_menu($rs) {
-    global $CFG;
-    $menu = array();
-    if ($rs && !rs_EOF($rs)) {
-        $keys = array_keys($rs->fields);
-        $key0=$keys[0];
-        $key1=$keys[1];
-        while (!$rs->EOF) {
-            $menu[$rs->fields[$key0]] = $rs->fields[$key1];
-            $rs->MoveNext();
-        }
-        /// Really DIRTY HACK for Oracle, but it's the only way to make it work
-        /// until we got all those NOT NULL DEFAULT '' out from Moodle
-        if ($CFG->dbfamily == 'oracle') {
-            array_walk($menu, 'onespace2empty');
-        }
-        /// End of DIRTY HACK
-        return $menu;
-    } else {
-        return false;
-    }
-}
-
-/**
- * Utility function 
- * Similar to recordset_to_menu 
- *
- * field1, field2 is needed because the order from get_records_sql is not reliable
- * @param records - records from get_records_sql() or get_records()
- * @param field1 - field to be used as menu index
- * @param field2 - feild to be used as coresponding menu value
- * @return mixed an associative array, or false if an error occured or the RecordSet was empty.
- */
-function records_to_menu($records, $field1, $field2) {
-
-    $menu = array();
-    foreach ($records as $record) {
-        $menu[$record->$field1] = $record->$field2;
-    }
-
-    if (!empty($menu)) {
-        return $menu;
-    } else {
-        return false; 
-    }
-}
-
-/**
- * Get the first two columns from a number of records as an associative array.
- *
- * Arguments as for @see function get_recordset.
- *
- * If no errors occur, and at least one records is found, the return value
- * is an associative whose keys come from the first field of each record,
- * and whose values are the corresponding second fields. If no records are found,
- * or an error occurs, false is returned.
- *
- * @param string $table the table to query.
- * @param string $field a field to check (optional).
- * @param string $value the value the field must have (requred if field1 is given, else optional).
- * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
- * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an associative array, or false if no records were found or an error occured.
- */
-function get_records_menu($table, $field='', $value='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
-    $rs = get_recordset($table, $field, $value, $sort, $fields, $limitfrom, $limitnum);
-    return recordset_to_menu($rs);
-}
-
-/**
- * Get the first two columns from a number of records as an associative array.
- *
- * Arguments as for @see function get_recordset_select.
- * Return value as for @see function get_records_menu.
- *
- * @param string $table The database table to be checked against.
- * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
- * @param string $sort Sort order (optional) - a valid SQL order parameter
- * @param string $fields A comma separated list of fields to be returned from the chosen table.
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an associative array, or false if no records were found or an error occured.
- */
-function get_records_select_menu($table, $select='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
-    $rs = get_recordset_select($table, $select, $sort, $fields, $limitfrom, $limitnum);
-    return recordset_to_menu($rs);
-}
-
-/**
- * Get the first two columns from a number of records as an associative array.
- *
- * Arguments as for @see function get_recordset_sql.
- * Return value as for @see function get_records_menu.
- *
- * @param string $sql The SQL string you wish to be executed.
- * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
- * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
- * @return mixed an associative array, or false if no records were found or an error occured.
- */
-function get_records_sql_menu($sql, $limitfrom='', $limitnum='') {
-    $rs = get_recordset_sql($sql, $limitfrom, $limitnum);
-    return recordset_to_menu($rs);
-}
-
-/**
- * Get a single value from a table row where all the given fields match the given values.
- *
- * @param string $table the table to query.
- * @param string $return the field to return the value of.
- * @param string $field1 the first field to check (optional).
- * @param string $value1 the value field1 must have (requred if field1 is given, else optional).
- * @param string $field2 the second field to check (optional).
- * @param string $value2 the value field2 must have (requred if field2 is given, else optional).
- * @param string $field3 the third field to check (optional).
- * @param string $value3 the value field3 must have (requred if field3 is given, else optional).
- * @return mixed the specified value, or false if an error occured.
- */
-function get_field($table, $return, $field1, $value1, $field2='', $value2='', $field3='', $value3='') {
-    global $CFG;
-    $select = where_clause($field1, $value1, $field2, $value2, $field3, $value3);
-    return get_field_sql('SELECT ' . $return . ' FROM ' . $CFG->prefix . $table . ' ' . $select);
-}
-
-/**
- * Get a single value from a table row where a particular select clause is true.
- *
- * @uses $CFG
- * @param string $table the table to query.
- * @param string $return the field to return the value of.
- * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
- * @return mixed the specified value, or false if an error occured.
- */
-function get_field_select($table, $return, $select) {
-    global $CFG;
-    if ($select) {
-        $select = 'WHERE '. $select;
-    }
-    return get_field_sql('SELECT ' . $return . ' FROM ' . $CFG->prefix . $table . ' ' . $select);
-}
-
-/**
- * Get a single value from a table.
- *
- * @param string $sql an SQL statement expected to return a single value.
- * @return mixed the specified value, or false if an error occured.
- */
-function get_field_sql($sql) {
-    global $CFG;
-
-/// Strip potential LIMIT uses arriving here, debugging them (MDL-7173)
-    $newsql = preg_replace('/ LIMIT [0-9, ]+$/is', '', $sql);
-    if ($newsql != $sql) {
-        debugging('Incorrect use of LIMIT clause (not cross-db) in call to get_field_sql(): ' . s($sql), DEBUG_DEVELOPER);
-        $sql = $newsql;
-    }
-
-    $rs = get_recordset_sql($sql, 0, 1);
-
-    if ($rs && $rs->RecordCount() == 1) {
-        /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
-        /// to '' (empty string) for Oracle. It's the only way to work with
-        /// all those NOT NULL DEFAULT '' fields until we definetively delete them
-        if ($CFG->dbfamily == 'oracle') {
-            $value = reset($rs->fields);
-            onespace2empty($value);
-            return $value;
-        }
-        /// End of DIRTY HACK
-        return reset($rs->fields);
-    } else {
-        return false;
-    }
-}
-
-/**
- * Get a single value from a table row where a particular select clause is true.
- *
- * @uses $CFG
- * @param string $table the table to query.
- * @param string $return the field to return the value of.
- * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
- * @return mixed|false Returns the value return from the SQL statment or false if an error occured.
- */
-function get_fieldset_select($table, $return, $select) {
-    global $CFG;
-    if ($select) {
-        $select = ' WHERE '. $select;
-    }
-    return get_fieldset_sql('SELECT ' . $return . ' FROM ' . $CFG->prefix . $table . $select);
-}
-
-/**
- * Get an array of data from one or more fields from a database
- * use to get a column, or a series of distinct values
- *
- * @uses $CFG
- * @uses $db
- * @param string $sql The SQL string you wish to be executed.
- * @return mixed|false Returns the value return from the SQL statment or false if an error occured.
- * @todo Finish documenting this function
- */
-function get_fieldset_sql($sql) {
-
-    global $db, $CFG;
-
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
-
-    $rs = $db->Execute($sql);
-    if (!$rs) {
-        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
-        if (!empty($CFG->dblogerror)) {
-            $debug=array_shift(debug_backtrace());
-            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql");
-        }
-        return false;
-    }
-
-    if ( !rs_EOF($rs) ) {
-        $keys = array_keys($rs->fields);
-        $key0 = $keys[0];
-        $results = array();
-        while (!$rs->EOF) {
-            array_push($results, $rs->fields[$key0]);
-            $rs->MoveNext();
-        }
-        /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
-        /// to '' (empty string) for Oracle. It's the only way to work with
-        /// all those NOT NULL DEFAULT '' fields until we definetively delete them
-        if ($CFG->dbfamily == 'oracle') {
-            array_walk($results, 'onespace2empty');
-        }
-        /// End of DIRTY HACK
-        rs_close($rs);
-        return $results;
-    } else {
-        rs_close($rs);
-        return false;
-    }
-}
-
-/**
- * Set a single field in every table row where all the given fields match the given values.
- *
- * @uses $CFG
- * @uses $db
- * @param string $table The database table to be checked against.
- * @param string $newfield the field to set.
- * @param string $newvalue the value to set the field to.
- * @param string $field1 the first field to check (optional).
- * @param string $value1 the value field1 must have (requred if field1 is given, else optional).
- * @param string $field2 the second field to check (optional).
- * @param string $value2 the value field2 must have (requred if field2 is given, else optional).
- * @param string $field3 the third field to check (optional).
- * @param string $value3 the value field3 must have (requred if field3 is given, else optional).
- * @return mixed An ADODB RecordSet object with the results from the SQL call or false.
- */
-function set_field($table, $newfield, $newvalue, $field1, $value1, $field2='', $value2='', $field3='', $value3='') {
-
-    global $CFG;
-
-    // Clear record_cache based on the parameters passed
-    // (individual record or whole table)
-    if ($CFG->rcache === true) {
-        if ($field1 == 'id') {
-            rcache_unset($table, $value1);
-        } else if ($field2 == 'id') {
-            rcache_unset($table, $value2);
-        } else if ($field3 == 'id') {
-            rcache_unset($table, $value3);
-        } else {
-            rcache_unset_table($table);
-        }
-    }
-
-    $select = where_clause($field1, $value1, $field2, $value2, $field3, $value3);
-
-    return set_field_select($table, $newfield, $newvalue, $select, true);
-}
-
-/**
- * Set a single field in every table row where the select statement evaluates to true.
- *
- * @uses $CFG
- * @uses $db
- * @param string $table The database table to be checked against.
- * @param string $newfield the field to set.
- * @param string $newvalue the value to set the field to.
- * @param string $select a fragment of SQL to be used in a where clause in the SQL call.
- * @param boolean $localcall Leave this set to false. (Should only be set to true by set_field.)
- * @return mixed An ADODB RecordSet object with the results from the SQL call or false.
- */
-function set_field_select($table, $newfield, $newvalue, $select, $localcall = false) {
-
-    global $db, $CFG;
-
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
-
-    if (!$localcall) {
-        if ($select) {
-            $select = 'WHERE ' . $select;
-        }
-
-        // Clear record_cache based on the parameters passed
-        // (individual record or whole table)
-        if ($CFG->rcache === true) {
-            rcache_unset_table($table);
-        }
-    }
-
-    $dataobject = new StdClass;
-    $dataobject->{$newfield} = $newvalue;
-    // Oracle DIRTY HACK -
-    if ($CFG->dbfamily == 'oracle') {
-        oracle_dirty_hack($table, $dataobject); // Convert object to the correct "empty" values for Oracle DB
-        $newvalue = $dataobject->{$newfield};
-    }
-    // End DIRTY HACK
-
-/// Under Oracle, MSSQL and PostgreSQL we have our own set field process
-/// If the field being updated is clob/blob, we use our alternate update here
-/// They will be updated later
-    if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') && !empty($select)) {
-    /// Detect lobs
-        $foundclobs = array();
-        $foundblobs = array();
-        db_detect_lobs($table, $dataobject, $foundclobs, $foundblobs);
-    }
-
-/// Under Oracle, MSSQL and PostgreSQL, finally, update all the Clobs and Blobs present in the record
-/// if we know we have some of them in the query
-    if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') && !empty($select) &&
-      (!empty($foundclobs) || !empty($foundblobs))) {
-        if (!db_update_lobs($table, $select, $foundclobs, $foundblobs)) {
-            return false; //Some error happened while updating LOBs
-        } else {
-            return true; //Everrything was ok
-        }
-    }
-
-/// NULL inserts - introduced in 1.9
-    if (is_null($newvalue)) {
-        $update = "$newfield = NULL";
-    } else {
-        $update = "$newfield = '$newvalue'";
-    }
-
-/// Arriving here, standard update
-    $sql = 'UPDATE '. $CFG->prefix . $table .' SET '.$update.' '.$select;
-    $rs = $db->Execute($sql);
-    if (!$rs) {
-        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
-        if (!empty($CFG->dblogerror)) {
-            $debug=array_shift(debug_backtrace());
-            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql");
-        }
-        return false;
-    }
-    return $rs;
-}
-
-/**
- * Delete the records from a table where all the given fields match the given values.
- *
- * @uses $CFG
- * @uses $db
- * @param string $table the table to delete from.
- * @param string $field1 the first field to check (optional).
- * @param string $value1 the value field1 must have (requred if field1 is given, else optional).
- * @param string $field2 the second field to check (optional).
- * @param string $value2 the value field2 must have (requred if field2 is given, else optional).
- * @param string $field3 the third field to check (optional).
- * @param string $value3 the value field3 must have (requred if field3 is given, else optional).
- * @return mixed An ADODB RecordSet object with the results from the SQL call or false.
- */
-function delete_records($table, $field1='', $value1='', $field2='', $value2='', $field3='', $value3='') {
-
-    global $db, $CFG;
-
-    // Clear record_cache based on the parameters passed
-    // (individual record or whole table)
-    if ($CFG->rcache === true) {
-        if ($field1 == 'id') {
-            rcache_unset($table, $value1);
-        } else if ($field2 == 'id') {
-            rcache_unset($table, $value2);
-        } else if ($field3 == 'id') {
-            rcache_unset($table, $value3);
-        } else {
-            rcache_unset_table($table);
-        }
-    }
-
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
-
-    $select = where_clause($field1, $value1, $field2, $value2, $field3, $value3);
-
-    $sql = 'DELETE FROM '. $CFG->prefix . $table .' '. $select;
-    $rs = $db->Execute($sql);
-    if (!$rs) {
-        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
-        if (!empty($CFG->dblogerror)) {
-            $debug=array_shift(debug_backtrace());
-            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql");
-        }
-        return false;
-    }
-    return $rs;
-}
-
-/**
- * Delete one or more records from a table
- *
- * @uses $CFG
- * @uses $db
- * @param string $table The database table to be checked against.
- * @param string $select A fragment of SQL to be used in a where clause in the SQL call (used to define the selection criteria).
- * @return object A PHP standard object with the results from the SQL call.
- * @todo Verify return type.
- */
-function delete_records_select($table, $select='') {
-
-    global $CFG, $db;
-
-    // Clear record_cache (whole table)
-    if ($CFG->rcache === true) {
-        rcache_unset_table($table);
-    }
-
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
-
-    if ($select) {
-        $select = 'WHERE '.$select;
-    }
-
-    $sql = 'DELETE FROM '. $CFG->prefix . $table .' '. $select;
-    $rs = $db->Execute($sql);
-    if (!$rs) {
-        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
-        if (!empty($CFG->dblogerror)) {
-            $debug=array_shift(debug_backtrace());
-            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql");
-        }
-        return false;
-    }
-    return $rs;
-}
-
-/**
- * Insert a record into a table and return the "id" field if required
- *
- * If the return ID isn't required, then this just reports success as true/false.
- * $dataobject is an object containing needed data
- *
- * @uses $db
- * @uses $CFG
- * @param string $table The database table to be checked against.
- * @param object $dataobject A data object with values for one or more fields in the record
- * @param bool $returnid Should the id of the newly created record entry be returned? If this option is not requested then true/false is returned.
- * @param string $primarykey (obsolete) This is now forced to be 'id'. 
- */
-function insert_record($table, $dataobject, $returnid=true, $primarykey='id') {
-
-    global $db, $CFG, $empty_rs_cache;
-
-    if (empty($db)) {
-        return false;
-    }
-
-/// Check we are handling a proper $dataobject
-    if (is_array($dataobject)) {
-        debugging('Warning. Wrong call to insert_record(). $dataobject must be an object. array found instead', DEBUG_DEVELOPER);
-        $dataobject = (object)$dataobject;
-    }
-
-/// Temporary hack as part of phasing out all access to obsolete user tables  XXX
-    if (!empty($CFG->rolesactive)) {
-        if (in_array($table, array('user_students', 'user_teachers', 'user_coursecreators', 'user_admins'))) {
-            if (debugging()) { var_dump(debug_backtrace()); }
-            print_error('This SQL relies on obsolete tables ('.$table.')!  Your code must be fixed by a developer.');
-        }
-    }
-
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
-
-/// In Moodle we always use auto-numbering fields for the primary key
-/// so let's unset it now before it causes any trouble later
-    unset($dataobject->{$primarykey});
-
-/// Get an empty recordset. Cache for multiple inserts.
-    if (empty($empty_rs_cache[$table])) {
-        /// Execute a dummy query to get an empty recordset
-        if (!$empty_rs_cache[$table] = $db->Execute('SELECT * FROM '. $CFG->prefix . $table .' WHERE '. $primarykey  .' = \'-1\'')) {
-            return false;
-        }
-    }
-
-    $rs = $empty_rs_cache[$table];
-
-/// Postgres doesn't have the concept of primary key built in
-/// and will return the OID which isn't what we want.
-/// The efficient and transaction-safe strategy is to
-/// move the sequence forward first, and make the insert
-/// with an explicit id.
-    if ( $CFG->dbfamily === 'postgres' && $returnid == true ) {
-        if ($nextval = (int)get_field_sql("SELECT NEXTVAL('{$CFG->prefix}{$table}_{$primarykey}_seq')")) {
-            $dataobject->{$primarykey} = $nextval;
-        }
-    }
-
-/// Begin DIRTY HACK
-    if ($CFG->dbfamily == 'oracle') {
-        oracle_dirty_hack($table, $dataobject); // Convert object to the correct "empty" values for Oracle DB
-    }
-/// End DIRTY HACK
-
-/// Under Oracle, MSSQL and PostgreSQL we have our own insert record process
-/// detect all the clob/blob fields and change their contents to @#CLOB#@ and @#BLOB#@
-/// saving them into $foundclobs and $foundblobs [$fieldname]->contents
-/// Same for mssql (only processing blobs - image fields)
-    if ($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') {
-        $foundclobs = array();
-        $foundblobs = array();
-        db_detect_lobs($table, $dataobject, $foundclobs, $foundblobs);
-    }
-
-/// Under Oracle, if the primary key inserted has been requested OR
-/// if there are LOBs to insert, we calculate the next value via
-/// explicit query to the sequence.
-/// Else, the pre-insert trigger will do the job, because the primary
-/// key isn't needed at all by the rest of PHP code
-    if ($CFG->dbfamily === 'oracle' && ($returnid == true || !empty($foundclobs) || !empty($foundblobs))) {
-    /// We need this here (move this function to dmlib?)
-        include_once($CFG->libdir . '/ddllib.php');
-        $xmldb_table = new XMLDBTable($table);
-        $seqname = find_sequence_name($xmldb_table);
-        if (!$seqname) {
-        /// Fallback, seqname not found, something is wrong. Inform and use the alternative getNameForObject() method
-            debugging('Sequence name for table ' . $table->getName() . ' not found', DEBUG_DEVELOPER);
-            $generator = new XMLDBoci8po();
-            $generator->setPrefix($CFG->prefix);
-            $seqname = $generator->getNameForObject($table, $primarykey, 'seq');
-        }
-        if ($nextval = (int)$db->GenID($seqname)) {
-            $dataobject->{$primarykey} = $nextval;
-        } else {
-            debugging('Not able to get value from sequence ' . $seqname, DEBUG_DEVELOPER);
-        }
-    }
-
-/// Get the correct SQL from adoDB
-    if (!$insertSQL = $db->GetInsertSQL($rs, (array)$dataobject, true)) {
-        return false;
-    }
-
-/// Under Oracle, MSSQL and PostgreSQL, replace all the '@#CLOB#@' and '@#BLOB#@' ocurrences to proper default values
-/// if we know we have some of them in the query
-    if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') &&
-      (!empty($foundclobs) || !empty($foundblobs))) {
-    /// Initial configuration, based on DB
-        switch ($CFG->dbfamily) {
-            case 'oracle':
-                $clobdefault = 'empty_clob()'; //Value of empty default clobs for this DB
-                $blobdefault = 'empty_blob()'; //Value of empty default blobs for this DB
-                break;
-            case 'mssql':
-            case 'postgres':
-                $clobdefault = 'null'; //Value of empty default clobs for this DB (under mssql this won't be executed
-                $blobdefault = 'null'; //Value of empty default blobs for this DB
-                break;
-        }
-        $insertSQL = str_replace("'@#CLOB#@'", $clobdefault, $insertSQL);
-        $insertSQL = str_replace("'@#BLOB#@'", $blobdefault, $insertSQL);
-    }
-
-/// Run the SQL statement
-    if (!$rs = $db->Execute($insertSQL)) {
-        debugging($db->ErrorMsg() .'<br /><br />'.s($insertSQL));
-        if (!empty($CFG->dblogerror)) {
-            $debug=array_shift(debug_backtrace());
-            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $insertSQL");
-        }
-        return false;
-    }
-
-/// Under Oracle and PostgreSQL, finally, update all the Clobs and Blobs present in the record
-/// if we know we have some of them in the query
-    if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'postgres') &&
-      !empty($dataobject->{$primarykey}) &&
-      (!empty($foundclobs) || !empty($foundblobs))) {
-        if (!db_update_lobs($table, $dataobject->{$primarykey}, $foundclobs, $foundblobs)) {
-            return false; //Some error happened while updating LOBs
-        }
-    }
-
-/// If a return ID is not needed then just return true now (but not in MSSQL DBs, where we may have some pending tasks)
-    if (!$returnid && $CFG->dbfamily != 'mssql') {
-        return true;
-    }
-
-/// We already know the record PK if it's been passed explicitly,
-/// or if we've retrieved it from a sequence (Postgres and Oracle).
-    if (!empty($dataobject->{$primarykey})) {
-        return $dataobject->{$primarykey};
-    }
-
-/// This only gets triggered with MySQL and MSQL databases
-/// however we have some postgres fallback in case we failed
-/// to find the sequence.
-    $id = $db->Insert_ID();
-
-/// Under MSSQL all the Clobs and Blobs (IMAGE) present in the record
-/// if we know we have some of them in the query
-    if (($CFG->dbfamily == 'mssql') &&
-      !empty($id) &&
-      (!empty($foundclobs) || !empty($foundblobs))) {
-        if (!db_update_lobs($table, $id, $foundclobs, $foundblobs)) {
-            return false; //Some error happened while updating LOBs
-        }
-    }
-
-    if ($CFG->dbfamily === 'postgres') {
-        // try to get the primary key based on id
-        if ( ($rs = $db->Execute('SELECT '. $primarykey .' FROM '. $CFG->prefix . $table .' WHERE oid = '. $id))
-             && ($rs->RecordCount() == 1) ) {
-            trigger_error("Retrieved $primarykey from oid on table $table because we could not find the sequence.");
-            return (integer)reset($rs->fields);
-        }
-        trigger_error('Failed to retrieve primary key after insert: SELECT '. $primarykey .
-                      ' FROM '. $CFG->prefix . $table .' WHERE oid = '. $id);
-        return false;
-    }
-
-    return (integer)$id;
-}
-
-/**
- * Update a record in a table
- *
- * $dataobject is an object containing needed data
- * Relies on $dataobject having a variable "id" to
- * specify the record to update
- *
- * @uses $CFG
- * @uses $db
- * @param string $table The database table to be checked against.
- * @param object $dataobject An object with contents equal to fieldname=>fieldvalue. Must have an entry for 'id' to map to the table specified.
- * @return bool
- */
-function update_record($table, $dataobject) {
-
-    global $db, $CFG;
-
-    if (! isset($dataobject->id) ) {
-        return false;
-    }
-
-/// Check we are handling a proper $dataobject
-    if (is_array($dataobject)) {
-        debugging('Warning. Wrong call to update_record(). $dataobject must be an object. array found instead', DEBUG_DEVELOPER);
-        $dataobject = (object)$dataobject;
-    }
-
-    // Remove this record from record cache since it will change
-    if (!empty($CFG->rcache)) { // no === here! breaks upgrade
-        rcache_unset($table, $dataobject->id);
-    }
-
-/// Temporary hack as part of phasing out all access to obsolete user tables  XXX
-    if (!empty($CFG->rolesactive)) {
-        if (in_array($table, array('user_students', 'user_teachers', 'user_coursecreators', 'user_admins'))) {
-            if (debugging()) { var_dump(debug_backtrace()); }
-            print_error('This SQL relies on obsolete tables ('.$table.')!  Your code must be fixed by a developer.');
-        }
-    }
-
-/// Begin DIRTY HACK
-    if ($CFG->dbfamily == 'oracle') {
-        oracle_dirty_hack($table, $dataobject); // Convert object to the correct "empty" values for Oracle DB
-    }
-/// End DIRTY HACK
-
-/// Under Oracle, MSSQL and PostgreSQL we have our own update record process
-/// detect all the clob/blob fields and delete them from the record being updated
-/// saving them into $foundclobs and $foundblobs [$fieldname]->contents
-/// They will be updated later
-    if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres')
-      && !empty($dataobject->id)) {
-    /// Detect lobs
-        $foundclobs = array();
-        $foundblobs = array();
-        db_detect_lobs($table, $dataobject, $foundclobs, $foundblobs, true);
-    }
-
-    // Determine all the fields in the table
-    if (!$columns = $db->MetaColumns($CFG->prefix . $table)) {
-        return false;
-    }
-    $data = (array)$dataobject;
-
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
-
-    // Pull out data matching these fields
-    $update = array();
-    foreach ($columns as $column) {
-        if ($column->name == 'id') {
-            continue;
-        }
-        if (array_key_exists($column->name, $data)) {
-            $key   = $column->name;
-            $value = $data[$key];
-            if (is_null($value)) {
-                $update[] = "$key = NULL"; // previously NULLs were not updated
-            } else if (is_bool($value)) {
-                $value = (int)$value;
-                $update[] = "$key = $value";   // lets keep pg happy, '' is not correct smallint MDL-13038
-            } else {
-                $update[] = "$key = '$value'"; // All incoming data is already quoted
-            }
-        }
-    }
-
-/// Only if we have fields to be updated (this will prevent both wrong updates +
-/// updates of only LOBs in Oracle
-    if ($update) {
-        $query = "UPDATE {$CFG->prefix}{$table} SET ".implode(',', $update)." WHERE id = {$dataobject->id}";
-        if (!$rs = $db->Execute($query)) {
-            debugging($db->ErrorMsg() .'<br /><br />'.s($query));
-            if (!empty($CFG->dblogerror)) {
-                $debug=array_shift(debug_backtrace());
-                error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $query");
-            }
-            return false;
-        }
-    }
-
-/// Under Oracle, MSSQL and PostgreSQL, finally, update all the Clobs and Blobs present in the record
-/// if we know we have some of them in the query
-    if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') &&
-        !empty($dataobject->id) &&
-        (!empty($foundclobs) || !empty($foundblobs))) {
-        if (!db_update_lobs($table, $dataobject->id, $foundclobs, $foundblobs)) {
-            return false; //Some error happened while updating LOBs
-        }
-    }
-
-    return true;
-}
-
-
-
-/**
- * Returns the proper SQL to do paging
- *
- * @uses $CFG
- * @param string $page Offset page number
- * @param string $recordsperpage Number of records per page
- * @deprecated Moodle 1.7 use the new $limitfrom, $limitnum available in all
- *             the get_recordXXX() funcions.
- * @return string
- */
-function sql_paging_limit($page, $recordsperpage) {
-    global $CFG;
-
-    debugging('Function sql_paging_limit() is deprecated. Replace it with the correct use of limitfrom, limitnum parameters', DEBUG_DEVELOPER);
-
-    switch ($CFG->dbfamily) {
-        case 'postgres':
-             return 'LIMIT '. $recordsperpage .' OFFSET '. $page;
-        default:
-             return 'LIMIT '. $page .','. $recordsperpage;
-    }
-}
-
-/**
- * Returns the proper SQL to do LIKE in a case-insensitive way
- *
- * Note the LIKE are case sensitive for Oracle. Oracle 10g is required to use
- * the caseinsensitive search using regexp_like() or NLS_COMP=LINGUISTIC :-(
- * See http://docs.moodle.org/en/XMLDB_Problems#Case-insensitive_searches
- *
- * @uses $CFG
- * @return string
- */
-function sql_ilike() {
-    global $CFG;
-
-    switch ($CFG->dbfamily) {
-        case 'postgres':
-             return 'ILIKE';
-        default:
-             return 'LIKE';
-    }
-}
-
-
-/**
- * Returns the proper SQL to do MAX
- *
- * @uses $CFG
- * @param string $field
- * @return string
- */
-function sql_max($field) {
-    global $CFG;
-
-    switch ($CFG->dbfamily) {
-        default:
-             return "MAX($field)";
-    }
-}
-
-/**
- * Returns the proper SQL (for the dbms in use) to concatenate $firstname and $lastname
- *
- * @uses $CFG
- * @param string $firstname User's first name
- * @param string $lastname User's last name
- * @return string
- */
-function sql_fullname($firstname='firstname', $lastname='lastname') {
-    return sql_concat($firstname, "' '", $lastname);
-}
-
-/**
- * Returns the proper SQL to do CONCAT between the elements passed
- * Can take many parameters - just a passthrough to $db->Concat()
- *
- * @uses $db
- * @param string $element
- * @return string
- */
-function sql_concat() {
-    global $db, $CFG;
-
-    $args = func_get_args();
-/// PostgreSQL requires at least one char element in the concat, let's add it
-/// here (at the beginning of the array) until ADOdb fixes it
-    if ($CFG->dbfamily == 'postgres' && is_array($args)) {
-        array_unshift($args , "''");
-    }
-    return call_user_func_array(array($db, 'Concat'), $args);
-}
-
-/**
- * Returns the proper SQL to do CONCAT between the elements passed
- * with a given separator
- *
- * @uses $db
- * @param string $separator
- * @param array  $elements
- * @return string
- */
-function sql_concat_join($separator="' '", $elements=array()) {
-    global $db;
-
-    // copy to ensure pass by value
-    $elem = $elements;
-
-    // Intersperse $elements in the array.
-    // Add items to the array on the fly, walking it
-    // _backwards_ splicing the elements in. The loop definition
-    // should skip first and last positions.
-    for ($n=count($elem)-1; $n > 0 ; $n--) {
-        array_splice($elem, $n, 0, $separator);
-    }
-    return call_user_func_array(array($db, 'Concat'), $elem);
-}
-
-/**
- * Returns the proper SQL to know if one field is empty.
- *
- * Note that the function behavior strongly relies on the
- * parameters passed describing the field so, please,  be accurate
- * when speciffying them.
- *
- * Also, note that this function is not suitable to look for
- * fields having NULL contents at all. It's all for empty values!
- *
- * This function should be applied in all the places where conditins of
- * the type:
- *
- *     ... AND fieldname = '';
- *
- * are being used. Final result should be:
- *
- *     ... AND ' . sql_isempty('tablename', 'fieldname', true/false, true/false);
- *
- * (see parameters description below)
- *
- * @param string $tablename name of the table (without prefix). Not used for now but can be
- *                          necessary in the future if we want to use some introspection using
- *                          meta information against the DB. /// TODO ///
- * @param string $fieldname name of the field we are going to check
- * @param boolean $nullablefield to specify if the field us nullable (true) or no (false) in the DB
- * @param boolean $textfield to specify if it is a text (also called clob) field (true) or a varchar one (false)
- * @return string the sql code to be added to check for empty values
- */
-function sql_isempty($tablename, $fieldname, $nullablefield, $textfield) {
-
-    global $CFG;
-
-    $sql = $fieldname . " = ''";
-
-    switch ($CFG->dbfamily) {
-        case 'mssql':
-            if ($textfield) {
-                $sql = sql_compare_text($fieldname) . " = ''";
-            }
-            break;
-        case 'oracle':
-            if ($nullablefield) {
-                $sql = $fieldname . " IS NULL";                     /// empties in nullable fields are stored as
-            } else {                                                /// NULLs
-                if ($textfield) {
-                    $sql = sql_compare_text($fieldname) . " = ' '"; /// oracle_dirty_hack inserts 1-whitespace
-                } else {                                            /// in NOT NULL varchar and text columns so
-                    $sql =  $fieldname . " = ' '";                  /// we need to look for that in any situation
-                }
-            }
-            break;
-    }
-
-    return ' ' . $sql . ' '; /// Adding spaces to avoid wrong SQLs due to concatenation
-}
-
-/**
- * Returns the proper SQL to know if one field is not empty.
- *
- * Note that the function behavior strongly relies on the
- * parameters passed describing the field so, please,  be accurate
- * when speciffying them.
- *
- * This function should be applied in all the places where conditions of
- * the type:
- *
- *     ... AND fieldname != '';
- *
- * are being used. Final result should be:
- *
- *     ... AND ' . sql_isnotempty('tablename', 'fieldname', true/false, true/false);
- *
- * (see parameters description below)
- *
- * @param string $tablename name of the table (without prefix). Not used for now but can be
- *                          necessary in the future if we want to use some introspection using
- *                          meta information against the DB. /// TODO ///
- * @param string $fieldname name of the field we are going to check
- * @param boolean $nullablefield to specify if the field us nullable (true) or no (false) in the DB
- * @param boolean $textfield to specify if it is a text (also called clob) field (true) or a varchar one (false)
- * @return string the sql code to be added to check for non empty values
- */
-function sql_isnotempty($tablename, $fieldname, $nullablefield, $textfield) {
-
-    return ' ( NOT ' . sql_isempty($tablename, $fieldname, $nullablefield, $textfield) . ') ';
-}
-
-/**
- * Returns the proper AS keyword to be used to aliase columns
- * SQL defines the keyword as optional and nobody but PG
- * seems to require it. This function should be used inside all
- * the statements using column aliases.
- * Note than the use of table aliases doesn't require the
- * AS keyword at all, only columns for postgres.
- * @uses $CFG
- * @ return string the keyword
- * @deprecated Moodle 1.7 because coding guidelines now enforce to use AS in column aliases
- */
-function sql_as() {
-    global $CFG, $db;
-
-    switch ($CFG->dbfamily) {
-        case 'postgres':
-            return 'AS';
-        default:
-            return '';
-    }
-}
-
-/**
- * Returns the empty string char used by every supported DB. To be used when
- * we are searching for that values in our queries. Only Oracle uses this
- * for now (will be out, once we migrate to proper NULLs if that days arrives)
- */
-function sql_empty() {
-    global $CFG;
-
-    switch ($CFG->dbfamily) {
-        case 'oracle':
-            return ' '; //Only Oracle uses 1 white-space
-        default:
-            return '';
-    }
-}
-
-/**
- * Returns the proper substr() function for each DB
- * Relies on ADOdb $db->substr property
- */
-function sql_substr() {
-
-    global $db;
-
-    return $db->substr;
-}
-
-/**
- * Returns the SQL text to be used to compare one TEXT (clob) column with
- * one varchar column, because some RDBMS doesn't support such direct
- * comparisons.
- * @param string fieldname the name of the TEXT field we need to order by
- * @param string number of chars to use for the ordering (defaults to 32)
- * @return string the piece of SQL code to be used in your statement.
- */
-function sql_compare_text($fieldname, $numchars=32) {
-    return sql_order_by_text($fieldname, $numchars);
-}
-
-
-/**
- * Returns the SQL text to be used to order by one TEXT (clob) column, because
- * some RDBMS doesn't support direct ordering of such fields.
- * Note that the use or queries being ordered by TEXT columns must be minimised,
- * because it's really slooooooow.
- * @param string fieldname the name of the TEXT field we need to order by
- * @param string number of chars to use for the ordering (defaults to 32)
- * @return string the piece of SQL code to be used in your statement.
- */
-function sql_order_by_text($fieldname, $numchars=32) {
-
-    global $CFG;
-
-    switch ($CFG->dbfamily) {
-        case 'mssql':
-            return 'CONVERT(varchar, ' . $fieldname . ', ' . $numchars . ')';
-            break;
-        case 'oracle':
-            return 'dbms_lob.substr(' . $fieldname . ', ' . $numchars . ',1)';
-            break;
-        default:
-            return $fieldname;
-    }
-}
-
-/**
- * Returns the SQL to be used in order to CAST one CHAR column to INTEGER.
- *
- * Be aware that the CHAR column you're trying to cast contains really
- * int values or the RDBMS will throw an error!
- *
- * @param string fieldname the name of the field to be casted
- * @param boolean text to specify if the original column is one TEXT (CLOB) column (true). Defaults to false.
- * @return string the piece of SQL code to be used in your statement.
- */
-function sql_cast_char2int($fieldname, $text=false) {
-
-    global $CFG;
-
-    $sql = '';
-
-    switch ($CFG->dbfamily) {
-        case 'mysql':
-            $sql = ' CAST(' . $fieldname . ' AS SIGNED) ';
-            break;
-        case 'postgres':
-            $sql = ' CAST(' . $fieldname . ' AS INT) ';
-            break;
-        case 'mssql':
-            if (!$text) {
-                $sql = ' CAST(' . $fieldname . ' AS INT) ';
-            } else {
-                $sql = ' CAST(' . sql_compare_text($fieldname) . ' AS INT) ';
-            }
-            break;
-        case 'oracle':
-            if (!$text) {
-                $sql = ' CAST(' . $fieldname . ' AS INT) ';
-            } else {
-                $sql = ' CAST(' . sql_compare_text($fieldname) . ' AS INT) ';
-            }
-            break;
-        default:
-            $sql = ' ' . $fieldname . ' ';
-    }
-
-    return $sql;
-}
-
-/**
- * Returns the SQL text to be used in order to perform one bitwise AND operation
- * between 2 integers.
- * @param integer int1 first integer in the operation
- * @param integer int2 second integer in the operation
- * @return string the piece of SQL code to be used in your statement.
- */
-function sql_bitand($int1, $int2) {
-
-    global $CFG;
-
-    switch ($CFG->dbfamily) {
-        case 'oracle':
-            return 'bitand((' . $int1 . '), (' . $int2 . '))';
-            break;
-        default:
-            return '((' . $int1 . ') & (' . $int2 . '))';
-    }
-}
-
-/**
- * Returns the SQL text to be used in order to perform one bitwise OR operation
- * between 2 integers.
- * @param integer int1 first integer in the operation
- * @param integer int2 second integer in the operation
- * @return string the piece of SQL code to be used in your statement.
- */
-function sql_bitor($int1, $int2) {
-
-    global $CFG;
-
-    switch ($CFG->dbfamily) {
-        case 'oracle':
-            return '((' . $int1 . ') + (' . $int2 . ') - ' . sql_bitand($int1, $int2) . ')';
-            break;
-        default:
-            return '((' . $int1 . ') | (' . $int2 . '))';
-    }
-}
-
-/**
- * Returns the SQL text to be used in order to perform one bitwise XOR operation
- * between 2 integers.
- * @param integer int1 first integer in the operation
- * @param integer int2 second integer in the operation
- * @return string the piece of SQL code to be used in your statement.
- */
-function sql_bitxor($int1, $int2) {
-
-    global $CFG;
-
-    switch ($CFG->dbfamily) {
-        case 'oracle':
-            return '(' . sql_bitor($int1, $int2) . ' - ' . sql_bitand($int1, $int2) . ')';
-            break;
-        case 'postgres':
-            return '((' . $int1 . ') # (' . $int2 . '))';
-            break;
-        default:
-            return '((' . $int1 . ') ^ (' . $int2 . '))';
-    }
-}
-
-/**
- * Returns the SQL text to be used in order to perform one bitwise NOT operation
- * with 1 integer.
- * @param integer int1 integer in the operation
- * @return string the piece of SQL code to be used in your statement.
- */
-function sql_bitnot($int1) {
-
-    global $CFG;
-
-    switch ($CFG->dbfamily) {
-        case 'oracle':
-            return '((0 - (' . $int1 . ')) - 1)';
-            break;
-        default:
-            return '(~(' . $int1 . '))';
-    }
+function modify_database($sqlfile='', $sqlstring='') {
+    error('modify_database() removed - use new XMLDB functions');
 }
 
-/**
- * Prepare a SQL WHERE clause to select records where the given fields match the given values.
- *
- * Prepares a where clause of the form
- *     WHERE field1 = value1 AND field2 = value2 AND field3 = value3
- * except that you need only specify as many arguments (zero to three) as you need.
- *
- * @param string $field1 the first field to check (optional).
- * @param string $value1 the value field1 must have (requred if field1 is given, else optional).
- * @param string $field2 the second field to check (optional).
- * @param string $value2 the value field2 must have (requred if field2 is given, else optional).
- * @param string $field3 the third field to check (optional).
- * @param string $value3 the value field3 must have (requred if field3 is given, else optional).
- */
 function where_clause($field1='', $value1='', $field2='', $value2='', $field3='', $value3='') {
-    if ($field1) {
-        $select = is_null($value1) ? "WHERE $field1 IS NULL" : "WHERE $field1 = '$value1'";
-        if ($field2) {
-            $select .= is_null($value2) ? " AND $field2 IS NULL" : " AND $field2 = '$value2'";
-            if ($field3) {
-                $select .= is_null($value3) ? " AND $field3 IS NULL" : " AND $field3 = '$value3'";
-            }
-        }
-    } else {
-        $select = '';
-    }
-    return $select;
-}
-
-/**
- * Get the data type of a table column, using an ADOdb MetaType() call.
- *
- * @uses $CFG
- * @uses $db
- * @param string $table The name of the database table
- * @param string $column The name of the field in the table
- * @return string Field type or false if error
- */
-
-function column_type($table, $column) {
-    global $CFG, $db;
-
-    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
-
-    $sql = 'SELECT '.$column.' FROM '.$CFG->prefix.$table.' WHERE 1=2';
-    if(!$rs = $db->Execute($sql)) {
-        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
-        if (!empty($CFG->dblogerror)) {
-            $debug=array_shift(debug_backtrace());
-            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql");
-        }
-        return false;
-    }
-
-    $field = $rs->FetchField(0);
-    return $rs->MetaType($field->type);
+    error('where_clause() removed - use new functions with $conditions parameter');
 }
 
-/**
- * This function will execute an array of SQL commands, returning
- * true/false if any error is found and stopping/continue as desired.
- * It's widely used by all the ddllib.php functions
- *
- * @param array sqlarr array of sql statements to execute
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @param boolean true if everything was ok, false if some error was found
- */
 function execute_sql_arr($sqlarr, $continue=true, $feedback=true) {
-
-    if (!is_array($sqlarr)) {
-        return false;
-    }
-
-    $status = true;
-    foreach($sqlarr as $sql) {
-        if (!execute_sql($sql, $feedback)) {
-            $status = false;
-            if (!$continue) {
-                break;
-            }
-        }
-    }
-    return $status;
-}
-
-/**
- * This internal function, called from setup.php, sets all the configuration
- * needed to work properly against any DB. It setups connection encoding
- * and some other variables.
- *
- * This function must contain the init code needed for each dbtype supported.
- */
-function configure_dbconnection() {
-
-    global $CFG, $db;
-
-    switch ($CFG->dbtype) {
-        case 'mysql':
-        case 'mysqli':
-            $db->Execute("SET NAMES 'utf8'");
-            break;
-        case 'postgres7':
-            $db->Execute("SET NAMES 'utf8'");
-            break;
-        case 'mssql':
-        case 'mssql_n':
-        case 'odbc_mssql':
-        /// No need to set charset. It must be specified in the driver conf
-        /// Allow quoted identifiers
-            $db->Execute('SET QUOTED_IDENTIFIER ON');
-        /// Force ANSI nulls so the NULL check was done by IS NULL and NOT IS NULL
-        /// instead of equal(=) and distinct(<>) simbols
-            $db->Execute('SET ANSI_NULLS ON');
-        /// Enable sybase quotes, so addslashes and stripslashes will use "'"
-            ini_set('magic_quotes_sybase', '1');
-        /// NOTE: Not 100% useful because GPC has been addslashed with the setting off
-        ///       so IT'S MANDATORY TO CHANGE THIS UNDER php.ini or .htaccess for this DB
-        ///       or to turn off magic_quotes to allow Moodle to do it properly
-            break;
-        case 'oci8po':
-        /// No need to set charset. It must be specified by the NLS_LANG env. variable
-        /// Enable sybase quotes, so addslashes and stripslashes will use "'"
-            ini_set('magic_quotes_sybase', '1');
-        /// NOTE: Not 100% useful because GPC has been addslashed with the setting off
-        ///       so IT'S MANDATORY TO ENABLE THIS UNDER php.ini or .htaccess for this DB
-        ///       or to turn off magic_quotes to allow Moodle to do it properly
-        /// Now set the decimal separator to DOT, Moodle & PHP will always send floats to
-        /// DB using DOTS. Manually introduced floats (if using other characters) must be
-        /// converted back to DOTs (like gradebook does)
-            $db->Execute("ALTER SESSION SET NLS_NUMERIC_CHARACTERS='.,'");
-            break;
-    }
-}
-
-/**
- * This function will handle all the records before being inserted/updated to DB for Oracle
- * installations. This is because the "special feature" of Oracle where the empty string is
- * equal to NULL and this presents a problem with all our currently NOT NULL default '' fields.
- *
- * Once Moodle DB will be free of this sort of false NOT NULLS, this hack could be removed safely
- *
- * Note that this function is 100% private and should be used, exclusively by DML functions
- * in this file. Also, this is considered a DIRTY HACK to be removed when possible. (stronk7)
- *
- * This function is private and must not be used outside dmllib at all
- *
- * @param $table string the table where the record is going to be inserted/updated (without prefix)
- * @param $dataobject object the object to be inserted/updated
- * @param $usecache boolean flag to determinate if we must use the per request cache of metadata
- *        true to use it, false to ignore and delete it
- */
-function oracle_dirty_hack ($table, &$dataobject, $usecache = true) {
-
-    global $CFG, $db, $metadata_cache;
-
-/// Init and delete metadata cache
-    if (!isset($metadata_cache) || !$usecache) {
-        $metadata_cache = array();
-    }
-
-/// For Oracle DB, empty strings are converted to NULLs in DB
-/// and this breaks a lot of NOT NULL columns currenty Moodle. In the future it's
-/// planned to move some of them to NULL, if they must accept empty values and this
-/// piece of code will become less and less used. But, for now, we need it.
-/// What we are going to do is to examine all the data being inserted and if it's
-/// an empty string (NULL for Oracle) and the field is defined as NOT NULL, we'll modify
-/// such data in the best form possible ("0" for booleans and numbers and " " for the
-/// rest of strings. It isn't optimal, but the only way to do so.
-/// In the oppsite, when retrieving records from Oracle, we'll decode " " back to
-/// empty strings to allow everything to work properly. DIRTY HACK.
-
-/// If the db isn't Oracle, return without modif
-    if ( $CFG->dbfamily != 'oracle') {
-        return;
-    }
-
-/// Get Meta info to know what to change, using the cached meta if exists
-    if (!isset($metadata_cache[$table])) {
-        $metadata_cache[$table] = array_change_key_case($db->MetaColumns($CFG->prefix . $table), CASE_LOWER);
-    }
-    $columns = $metadata_cache[$table];
-/// Iterate over all the fields in the insert, transforming values
-/// in the best possible form
-    foreach ($dataobject as $fieldname => $fieldvalue) {
-    /// If the field doesn't exist in metadata, skip
-        if (!isset($columns[strtolower($fieldname)])) {
-            continue;
-        }
-    /// If the field ins't VARCHAR or CLOB, skip
-        if ($columns[strtolower($fieldname)]->type != 'VARCHAR2' && $columns[strtolower($fieldname)]->type != 'CLOB') {
-            continue;
-        }
-    /// If the field isn't NOT NULL, skip (it's nullable, so accept empty values)
-        if (!$columns[strtolower($fieldname)]->not_null) {
-            continue;
-        }
-    /// If the value isn't empty, skip
-        if (!empty($fieldvalue)) {
-            continue;
-        }
-    /// Now, we have one empty value, going to be inserted to one NOT NULL, VARCHAR2 or CLOB field
-    /// Try to get the best value to be inserted
-
-    /// The '0' string doesn't need any transformation, skip
-        if ($fieldvalue === '0') {
-            continue;
-        }
-
-    /// Transformations start
-        if (gettype($fieldvalue) == 'boolean') {
-            $dataobject->$fieldname = '0'; /// Transform false to '0' that evaluates the same for PHP
-        } else if (gettype($fieldvalue) == 'integer') {
-            $dataobject->$fieldname = '0'; /// Transform 0 to '0' that evaluates the same for PHP
-        } else if (gettype($fieldvalue) == 'NULL') {
-            $dataobject->$fieldname = '0'; /// Transform NULL to '0' that evaluates the same for PHP
-        } else if ($fieldvalue === '') {
-            $dataobject->$fieldname = ' '; /// Transform '' to ' ' that DONT'T EVALUATE THE SAME
-                                           /// (we'll transform back again on get_records_XXX functions and others)!!
-        }
-    }
-}
-/// End of DIRTY HACK
-
-/**
- * This function will search for all the CLOBs and BLOBs fields passed in the dataobject, replacing
- * their contents by the fixed strings '@#CLOB#@' and '@#BLOB#@' and returning one array for all the
- * found CLOBS and another for all the found BLOBS
- * Used by Oracle drivers to perform the two-step insertion/update of LOBs and
- * by MSSQL to perform the same exclusively for BLOBs (IMAGE fields)
- *
- * This function is private and must not be used outside dmllib at all
- *
- * @param $table string the table where the record is going to be inserted/updated (without prefix)
- * @param $dataobject object the object to be inserted/updated
- * @param $clobs array of clobs detected
- * @param $dataobject array of blobs detected
- * @param $unset boolean to specify if we must unset found LOBs from the original object (true) or
- *        just return them modified to @#CLOB#@ and @#BLOB#@ (false)
- * @param $usecache boolean flag to determinate if we must use the per request cache of metadata
- *        true to use it, false to ignore and delete it
- */
-function db_detect_lobs ($table, &$dataobject, &$clobs, &$blobs, $unset = false, $usecache = true) {
-
-    global $CFG, $db, $metadata_cache;
-
-    $dataarray = (array)$dataobject; //Convert to array. It's supposed that PHP 4.3 doesn't iterate over objects
-
-/// Initial configuration, based on DB
-    switch ($CFG->dbfamily) {
-        case 'oracle':
-            $clobdbtype = 'CLOB'; //Name of clobs for this DB
-            $blobdbtype = 'BLOB'; //Name of blobs for this DB
-            break;
-        case 'mssql':
-            $clobdbtype = 'NOTPROCESSES'; //Name of clobs for this DB (under mssql flavours we don't process CLOBS)
-            $blobdbtype = 'IMAGE'; //Name of blobs for this DB
-            break;
-        case 'postgres':
-            $clobdbtype = 'NOTPROCESSES'; //Name of clobs for this DB (under postgres flavours we don't process CLOBS)
-            $blobdbtype = 'BYTEA'; //Name of blobs for this DB
-            break;
-        default:
-            return; //Other DB doesn't need this two step to happen, prevent continue
-    }
-
-/// Init and delete metadata cache
-    if (!isset($metadata_cache) || !$usecache) {
-        $metadata_cache = array();
-    }
-
-/// Get Meta info to know what to change, using the cached meta if exists
-    if (!isset($metadata_cache[$table])) {
-        $metadata_cache[$table] = array_change_key_case($db->MetaColumns($CFG->prefix . $table), CASE_LOWER);
-    }
-    $columns = $metadata_cache[$table];
-
-    foreach ($dataarray as $fieldname => $fieldvalue) {
-    /// If the field doesn't exist in metadata, skip
-        if (!isset($columns[strtolower($fieldname)])) {
-            continue;
-        }
-    /// If the field is CLOB, update its value to '@#CLOB#@' and store it in the $clobs array
-        if (strtoupper($columns[strtolower($fieldname)]->type) == $clobdbtype) {
-        /// Oracle optimization. CLOBs under 4000cc can be directly inserted (no need to apply 2-phases to them)
-            if ($CFG->dbfamily == 'oracle' && strlen($dataobject->$fieldname) < 4000) {
-                continue;
-            }
-            $clobs[$fieldname] = $dataobject->$fieldname;
-            if ($unset) {
-                unset($dataobject->$fieldname);
-            } else {
-                $dataobject->$fieldname = '@#CLOB#@';
-            }
-            continue;
-        }
-
-    /// If the field is BLOB OR IMAGE OR BYTEA, update its value to '@#BLOB#@' and store it in the $blobs array
-        if (strtoupper($columns[strtolower($fieldname)]->type) == $blobdbtype) {
-            $blobs[$fieldname] = $dataobject->$fieldname;
-            if ($unset) {
-                unset($dataobject->$fieldname);
-            } else {
-                $dataobject->$fieldname = '@#BLOB#@';
-            }
-            continue;
-        }
-    }
-}
-
-/**
- * This function will iterate over $clobs and $blobs array, executing the needed
- * UpdateClob() and UpdateBlob() ADOdb function calls to store LOBs contents properly
- * Records to be updated are always searched by PK (id always!)
- *
- * Used by Orace CLOBS and BLOBS and MSSQL IMAGES
- *
- * This function is private and must not be used outside dmllib at all
- *
- * @param $table string the table where the record is going to be inserted/updated (without prefix)
- * @param $sqlcondition mixed value defining the records to be LOB-updated. It it's a number, must point
- *        to the PK og the table (id field), else it's processed as one harcoded SQL condition (WHERE clause)
- * @param $clobs array of clobs to be updated
- * @param $blobs array of blobs to be updated
- */
-function db_update_lobs ($table, $sqlcondition, &$clobs, &$blobs) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-/// Initial configuration, based on DB
-    switch ($CFG->dbfamily) {
-        case 'oracle':
-            $clobdbtype = 'CLOB'; //Name of clobs for this DB
-            $blobdbtype = 'BLOB'; //Name of blobs for this DB
-            break;
-        case 'mssql':
-            $clobdbtype = 'NOTPROCESSES'; //Name of clobs for this DB (under mssql flavours we don't process CLOBS)
-            $blobdbtype = 'IMAGE'; //Name of blobs for this DB
-            break;
-        case 'postgres':
-            $clobdbtype = 'NOTPROCESSES'; //Name of clobs for this DB (under postgres flavours we don't process CLOBS)
-            $blobdbtype = 'BYTEA'; //Name of blobs for this DB
-            break;
-        default:
-            return; //Other DB doesn't need this two step to happen, prevent continue
-    }
-
-/// Calculate the update sql condition
-    if (is_numeric($sqlcondition)) { /// If passing a number, it's the PK of the table (id)
-        $sqlcondition = 'id=' . $sqlcondition;
-    } else { /// Else, it's a formal standard SQL condition, we try to delete the WHERE in case it exists
-        $sqlcondition = trim(preg_replace('/^WHERE/is', '', trim($sqlcondition)));
-    }
-
-/// Update all the clobs
-    if ($clobs) {
-        foreach ($clobs as $key => $value) {
-
-            if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; }; /// Count the extra updates in PERF
-
-        /// Oracle CLOBs doesn't like quoted strings (are inserted via prepared statemets)
-            if ($CFG->dbfamily == 'oracle') {
-                $value = stripslashes_safe($value);
-            }
-
-            if (!$db->UpdateClob($CFG->prefix.$table, $key, $value, $sqlcondition)) {
-                $status = false;
-                $statement = "UpdateClob('$CFG->prefix$table', '$key', '" . substr($value, 0, 100) . "...', '$sqlcondition')";
-                debugging($db->ErrorMsg() ."<br /><br />".s($statement));
-                if (!empty($CFG->dblogerror)) {
-                    $debug=array_shift(debug_backtrace());
-                    error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $statement");
-                }
-            }
-        }
-    }
-/// Update all the blobs
-    if ($blobs) {
-        foreach ($blobs as $key => $value) {
-
-            if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; }; /// Count the extra updates in PERF
-
-        /// Oracle, MSSQL and PostgreSQL BLOBs doesn't like quoted strings (are inserted via prepared statemets)
-            if ($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') {
-                $value = stripslashes_safe($value);
-            }
-
-            if(!$db->UpdateBlob($CFG->prefix.$table, $key, $value, $sqlcondition)) {
-                $status = false;
-                $statement = "UpdateBlob('$CFG->prefix$table', '$key', '" . substr($value, 0, 100) . "...', '$sqlcondition')";
-                debugging($db->ErrorMsg() ."<br /><br />".s($statement));
-                if (!empty($CFG->dblogerror)) {
-                    $debug=array_shift(debug_backtrace());
-                    error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $statement");
-                }
-            }
-        }
-    }
-    return $status;
-}
-
-/**
- * Set cached record.
- *
- * If you have called rcache_getforfill() before, it will also
- * release the lock.
- *
- * This function is private and must not be used outside dmllib at all
- *
- * @param $table string
- * @param $id integer
- * @param $rec obj
- * @return bool
- */
-function rcache_set($table, $id, $rec) {
-    global $CFG, $MCACHE, $rcache;
-
-    if ($CFG->cachetype === 'internal') {
-        if (!isset($rcache->data[$table])) {
-            $rcache->data[$table] = array();
-        }
-        if (!isset($rcache->data[$table][$id]) and count($rcache->data[$table]) > $CFG->intcachemax) {
-            // release oldes record 
-            reset($rcache->data[$table]);
-            $key = key($rcache->data[$table]);
-            unset($rcache->data[$table][$key]);
-        }
-        $rcache->data[$table][$id] = clone($rec);
-    } else {
-        $key   = $table . '|' . $id;
-
-        if (isset($MCACHE)) {
-            // $table is a flag used to mark
-            // a table as dirty & uncacheable
-            // when an UPDATE or DELETE not bound by ID
-            // is taking place
-            if (!$MCACHE->get($table)) {
-                // this will also release the _forfill lock
-                $MCACHE->set($key, $rec, $CFG->rcachettl);
-            }
-        }
-    }
-    return true;
-
-}
-
-/**
- * Unset cached record if it exists.
- *
- * This function is private and must not be used outside dmllib at all
- *
- * @param $table string
- * @param $id integer
- * @return bool
- */
-function rcache_unset($table, $id) {
-    global $CFG, $MCACHE, $rcache;
-
-    if ($CFG->cachetype === 'internal') {
-        if (isset($rcache->data[$table][$id])) {
-            unset($rcache->data[$table][$id]);
-        }
-    } else {
-        $key   = $table . '|' . $id;
-        if (isset($MCACHE)) {
-            $MCACHE->delete($key);
-        }
-    }
-    return true;
-}
-
-/**
- * Get cached record if available. ONLY use if you
- * are trying to get the cached record and will NOT
- * fetch it yourself if not cached.
- *
- * Use rcache_getforfill() if you are going to fetch
- * the record if not cached...
- *
- * This function is private and must not be used outside dmllib at all
- *
- * @param $table string
- * @param $id integer
- * @return mixed object-like record on cache hit, false otherwise
- */
-function rcache_get($table, $id) {
-    global $CFG, $MCACHE, $rcache;
-
-    if ($CFG->cachetype === 'internal') {
-        if (isset($rcache->data[$table][$id])) {
-            $rcache->hits++;
-            return clone($rcache->data[$table][$id]);
-        } else {
-            $rcache->misses++;
-            return false;
-        }
-    }
-
-    if (isset($MCACHE)) {
-        $key   = $table . '|' . $id;
-        // we set $table as a flag used to mark
-        // a table as dirty & uncacheable
-        // when an UPDATE or DELETE not bound by ID
-        // is taking place
-        if ($MCACHE->get($table)) {
-            $rcache->misses++;
-            return false;
-        } else {
-            $rec = $MCACHE->get($key);
-            if (!empty($rec)) {
-                $rcache->hits++;
-                return $rec;
-            } else {
-                $rcache->misses++;
-                return false;
-            }
-        }
-    }
-    return false;
-}
-
-/**
- * Get cached record if available. In most cases you want
- * to use this function -- namely if you are trying to get
- * the cached record and will fetch it yourself if not cached.
- * (and set the cache ;-)
- *
- * Uses the getforfill caching mechanism. See lib/eaccelerator.class.php
- * for a detailed description of the technique.
- *
- * Note: if you call rcache_getforfill() you are making an implicit promise
- * that if the cache is empty, you will later populate it, or cancel the promise
- * calling rcache_releaseforfill();
- *
- * This function is private and must not be used outside dmllib at all
- *
- * @param $table string
- * @param $id integer
- * @return mixed object-like record on cache hit, false otherwise
- */
-function rcache_getforfill($table, $id) {
-    global $CFG, $MCACHE, $rcache;
-
-    if ($CFG->cachetype === 'internal') {
-        return rcache_get($table, $id);
-    }
-
-    if (isset($MCACHE)) {
-        $key   = $table . '|' . $id;
-        // if $table is set - we won't take the
-        // lock either
-        if ($MCACHE->get($table)) {
-            $rcache->misses++;
-            return false;
-        }
-        $rec = $MCACHE->getforfill($key);
-        if (!empty($rec)) {
-            $rcache->hits++;
-            return $rec;
-        }
-        $rcache->misses++;
-        return false;
-    }
-    return false;
-}
-
-/**
- * Release the exclusive lock obtained by
- * rcache_getforfill(). See rcache_getforfill()
- * for more details.
- *
- * This function is private and must not be used outside dmllib at all
- *
- * @param $table string
- * @param $id integer
- * @return bool
- */
-function rcache_releaseforfill($table, $id) {
-    global $CFG, $MCACHE;
-
-    if (isset($MCACHE)) {
-        $key   = $table . '|' . $id;
-        return $MCACHE->releaseforfill($key);
-    }
-    return true;
-}
-
-/**
- * Remove or invalidate all rcache entries related to
- * a table. Not all caching mechanisms cluster entries
- * by table so in those cases we use alternative strategies.
- *
- * This function is private and must not be used outside dmllib at all
- *
- * @param $table string the table to invalidate records for
- * @return bool
- */
-function rcache_unset_table ($table) {
-    global $CFG, $MCACHE, $rcache;
-
-    if ($CFG->cachetype === 'internal') {
-        if (isset($rcache->data[$table])) {
-            unset($rcache->data[$table]);
-        }
-        return true;
-    }
-
-    if (isset($MCACHE)) {
-        // at least as long as content keys to ensure they expire
-        // before the dirty flag
-        $MCACHE->set($table, true, $CFG->rcachettl);
-    }
-    return true;
+    error('execute_sql_arr() removed');
 }
-
-?>
Index: lib/moodlelib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/moodlelib.php,v
retrieving revision 1.1044
diff -u -r1.1044 moodlelib.php
--- lib/moodlelib.php	12 May 2008 14:41:35 -0000	1.1044
+++ lib/moodlelib.php	15 May 2008 21:11:09 -0000
@@ -1432,15 +1432,13 @@
 }
 
 /**
- * ?
+ * Returns cached timezone record for given $timezonename
  *
- * @uses $CFG
- * @uses $db
- * @param string $timezonename ?
- * @return object
+ * @param string $timezonename
+ * @return mixed timezonerecord object or false
  */
 function get_timezone_record($timezonename) {
-    global $CFG, $db;
+    global $CFG, $DB;
     static $cache = NULL;
 
     if ($cache === NULL) {
@@ -1451,8 +1449,8 @@
         return $cache[$timezonename];
     }
 
-    return $cache[$timezonename] = get_record_sql('SELECT * FROM '.$CFG->prefix.'timezone
-                                      WHERE name = '.$db->qstr($timezonename).' ORDER BY year DESC', true);
+    return $cache[$timezonename] = $DB->get_record_sql('SELECT * FROM {timezone}
+                                                        WHERE name = ? ORDER BY year DESC', array($timezonename), true); 
 }
 
 /**
@@ -2776,16 +2774,14 @@
 /**
  * Returns an array of user fields
  *
- * @uses $CFG
- * @uses $db
  * @return array User field/column names
  */
 function get_user_fieldnames() {
+    global $DB;
 
-    global $CFG, $db;
-
-    $fieldarray = $db->MetaColumnNames($CFG->prefix.'user');
-    unset($fieldarray['ID']);
+    $fieldarray = $DB->get_columns('user');
+    unset($fieldarray['id']);
+    $fieldarray = array_keys($fieldarray);
 
     return $fieldarray;
 }
@@ -7525,7 +7521,7 @@
  ***
  **/
 function get_performance_info() {
-    global $CFG, $PERF, $rcache;
+    global $CFG, $PERF;
 
     $info = array();
     $info['html'] = '';         // holds userfriendly HTML representation
@@ -7602,14 +7598,14 @@
         $info['txt'] .= "serverload: {$info['serverload']} ";
     }
 
-    if (isset($rcache->hits) && isset($rcache->misses)) {
+/*    if (isset($rcache->hits) && isset($rcache->misses)) {
         $info['rcachehits'] = $rcache->hits;
         $info['rcachemisses'] = $rcache->misses;
         $info['html'] .= '<span class="rcache">Record cache hit/miss ratio : '.
             "{$rcache->hits}/{$rcache->misses}</span> ";
         $info['txt'] .= 'rcache: '.
             "{$rcache->hits}/{$rcache->misses} ";
-    }
+    }*/
     $info['html'] = '<div class="performanceinfo">'.$info['html'].'</div>';
     return $info;
 }
Index: lib/accesslib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/accesslib.php,v
retrieving revision 1.484
diff -u -r1.484 accesslib.php
--- lib/accesslib.php	15 May 2008 03:07:23 -0000	1.484
+++ lib/accesslib.php	15 May 2008 21:10:51 -0000
@@ -1,4 +1,4 @@
-<?php // $Id: accesslib.php,v 1.484 2008/05/15 03:07:23 dongsheng Exp $
+<?php // $Id: accesslib.php,v 1.483 2008/05/12 15:28:34 tjhunt Exp $
 
 ///////////////////////////////////////////////////////////////////////////
 //                                                                       //
@@ -155,7 +155,7 @@
 define('ROLENAME_ALIAS', 1);   // the name as defined by a role alias 
 define('ROLENAME_BOTH', 2);    // Both, like this:  Role alias (Original)
 
-require_once($CFG->dirroot.'/group/lib.php');
+require_once($CFG->dirroot.'/group/lib.php'); // TODO: verify and remove in 2.0
 
 $context_cache    = array();    // Cache of all used context objects for performance (by level and instance)
 $context_cache_id = array();    // Index to above cache by id
@@ -165,6 +165,8 @@
 $RDEFS = array(); // role definitions cache - helps a lot with mem usage in cron
 
 function get_role_context_caps($roleid, $context) {
+    global $DB;
+
     //this is really slow!!!! - do not use above course context level!
     $result = array();
     $result[$context->id] = array();
@@ -173,7 +175,7 @@
     $searchcontexts = array_reverse(get_parent_contexts($context));
     array_push($searchcontexts, $context->id);
     foreach ($searchcontexts as $cid) {
-        if ($capabilities = get_records_select('role_capabilities', "roleid = $roleid AND contextid = $cid")) {
+        if ($capabilities = $DB->get_records('role_capabilities', array('roleid'=>$roleid, 'contextid'=>$cid))) {
             foreach ($capabilities as $cap) {
                 if (!array_key_exists($cap->capability, $result[$context->id])) {
                     $result[$context->id][$cap->capability] = 0;
@@ -186,7 +188,7 @@
     // now go through the contexts bellow given context
     $searchcontexts = array_keys(get_child_contexts($context));
     foreach ($searchcontexts as $cid) {
-        if ($capabilities = get_records_select('role_capabilities', "roleid = $roleid AND contextid = $cid")) {
+        if ($capabilities = $DB->get_records('role_capabilities', array('roleid'=>$roleid, 'contextid'=>$cid))) {
             foreach ($capabilities as $cap) {
                 if (!array_key_exists($cap->contextid, $result)) {
                     $result[$cap->contextid] = array();
@@ -207,7 +209,7 @@
  */
 function get_role_access($roleid, $accessdata=NULL) {
 
-    global $CFG;
+    global $CFG, $DB;
 
     /* Get it in 1 cheap DB query...
      * - relevant role caps at the root and down
@@ -226,12 +228,13 @@
     //
     $sql = "SELECT ctx.path,
                    rc.capability, rc.permission
-            FROM {$CFG->prefix}context ctx
-            JOIN {$CFG->prefix}role_capabilities rc
-              ON rc.contextid=ctx.id
-            WHERE rc.roleid = {$roleid}
-                  AND ctx.contextlevel <= ".CONTEXT_COURSE."
-            ORDER BY ctx.depth, ctx.path";
+              FROM {context} ctx
+              JOIN {role_capabilities} rc
+                   ON rc.contextid=ctx.id
+             WHERE rc.roleid = ?
+                   AND ctx.contextlevel <= ".CONTEXT_COURSE."
+          ORDER BY ctx.depth, ctx.path";
+    $params = array($roleid);
 
     // we need extra caching in cron only
     if (defined('FULLME') and FULLME === 'cron') {
@@ -239,11 +242,11 @@
 
         if (!isset($cron_cache[$roleid])) {
             $cron_cache[$roleid] = array();
-            if ($rs = get_recordset_sql($sql)) {
-                while ($rd = rs_fetch_next_record($rs)) {
+            if ($rs = $DB->get_recordset_sql($sql, $params)) {
+                foreach ($rs as $rd) {
                     $cron_cache[$roleid][] = $rd;
                 }
-                rs_close($rs);
+                $rs->close();
             }
         }
 
@@ -253,13 +256,13 @@
         }
         
     } else {
-        if ($rs = get_recordset_sql($sql)) {
-            while ($rd = rs_fetch_next_record($rs)) {
+        if ($rs = $DB->get_recordset_sql($sql, $params)) {
+            foreach ($rs as $rd) {
                 $k = "{$rd->path}:{$roleid}";
                 $accessdata['rdef'][$k][$rd->capability] = $rd->permission;
             }
             unset($rd);
-            rs_close($rs);
+            $rs->close();
         }
     }
 
@@ -274,7 +277,7 @@
  */
 function get_default_frontpage_role_access($roleid, $accessdata=NULL) {
 
-    global $CFG;
+    global $CFG, $DB;
     
     $frontpagecontext = get_context_instance(CONTEXT_COURSE, SITEID);
     $base = '/'. SYSCONTEXTID .'/'. $frontpagecontext->id;
@@ -284,21 +287,22 @@
     //
     $sql = "SELECT ctx.path,
                    rc.capability, rc.permission
-            FROM {$CFG->prefix}context ctx
-            JOIN {$CFG->prefix}role_capabilities rc
-              ON rc.contextid=ctx.id
-            WHERE rc.roleid = {$roleid}
-                  AND (ctx.id = ".SYSCONTEXTID." OR ctx.path LIKE '$base/%')
-                  AND ctx.contextlevel <= ".CONTEXT_COURSE."
-            ORDER BY ctx.depth, ctx.path";             
+              FROM {context} ctx
+              JOIN {role_capabilities} rc
+                   ON rc.contextid=ctx.id
+             WHERE rc.roleid = ?
+                   AND (ctx.id = ".SYSCONTEXTID." OR ctx.path LIKE ?)
+                   AND ctx.contextlevel <= ".CONTEXT_COURSE."
+          ORDER BY ctx.depth, ctx.path";
+    $params = array($roleid, "$base/%");
             
-    if ($rs = get_recordset_sql($sql)) {
-        while ($rd = rs_fetch_next_record($rs)) {
+    if ($rs = $DB->get_recordset_sql($sql, $params)) {
+        foreach ($rs as $rd) {
             $k = "{$rd->path}:{$roleid}";
             $accessdata['rdef'][$k][$rd->capability] = $rd->permission;
         }
         unset($rd);
-        rs_close($rs);
+        $rs->close();
     }
 
     return $accessdata;
@@ -310,7 +314,7 @@
  * @return object role
  */
 function get_guest_role() {
-    global $CFG;
+    global $CFG, $DB;
 
     if (empty($CFG->guestroleid)) {
         if ($roles = get_roles_with_capability('moodle/legacy:guest', CAP_ALLOW)) {
@@ -322,7 +326,7 @@
             return false;
         }
     } else {
-        if ($guestrole = get_record('role','id', $CFG->guestroleid)) {
+        if ($guestrole = $DB->get_record('role', array('id'=>$CFG->guestroleid))) {
             return $guestrole;
         } else {
             //somebody is messing with guest roles, remove incorrect setting and try to find a new one
@@ -342,7 +346,7 @@
  * @return bool
  */
 function has_capability($capability, $context, $userid=NULL, $doanything=true) {
-    global $USER, $ACCESS, $CFG, $DIRTYCONTEXTS;
+    global $USER, $ACCESS, $CFG, $DIRTYCONTEXTS, $DB;
 
     // the original $CONTEXT here was hiding serious errors
     // for security reasons do not reuse previous context
@@ -356,7 +360,7 @@
         static $capsnames = null; // one request per page only
         
         if (is_null($capsnames)) {
-            if ($caps = get_records('capabilities', '', '', '', 'id, name')) {
+            if ($caps = $DB->get_records('capabilities', null, '', 'id, name')) {
                 $capsnames = array();
                 foreach ($caps as $cap) {
                     $capsnames[$cap->name] = true;
@@ -515,21 +519,22 @@
  * @returns bool $isadmin
  */
 function is_siteadmin($userid) {
-    global $CFG;
+    global $CFG, $DB;
 
     $sql = "SELECT SUM(rc.permission)
-            FROM " . $CFG->prefix . "role_capabilities rc
-            JOIN " . $CFG->prefix . "context ctx 
-              ON ctx.id=rc.contextid
-            JOIN " . $CFG->prefix . "role_assignments ra
-              ON ra.roleid=rc.roleid AND ra.contextid=ctx.id
-            WHERE ctx.contextlevel=10
-              AND ra.userid={$userid}
-              AND rc.capability IN ('moodle/site:config', 'moodle/legacy:admin', 'moodle/site:doanything')       
-            GROUP BY rc.capability
+              FROM {role_capabilities} rc
+              JOIN {context} ctx 
+                   ON ctx.id=rc.contextid
+              JOIN {role_assignments} ra
+                   ON ra.roleid=rc.roleid AND ra.contextid=ctx.id
+             WHERE ctx.contextlevel=10
+                   AND ra.userid=?
+                   AND rc.capability IN ('moodle/site:config', 'moodle/legacy:admin', 'moodle/site:doanything')       
+          GROUP BY rc.capability
             HAVING SUM(rc.permission) > 0";
+    $params = array($userid);
 
-    $isadmin = record_exists_sql($sql);
+    $isadmin = $DB->record_exists_sql($sql, $params);
     return $isadmin;
 }
 
@@ -841,7 +846,7 @@
 function require_capability($capability, $context, $userid=NULL, $doanything=true,
                             $errormessage='nopermissions', $stringfile='') {
 
-    global $USER, $CFG;
+    global $USER, $CFG, $DB;
 
     /* Empty $userid means current user, if the current user is not logged in,
      * then make sure they are (if needed).
@@ -855,10 +860,10 @@
             require_login($context->instanceid);
 
         } else if ($context->contextlevel == CONTEXT_MODULE) {
-            if (!$cm = get_record('course_modules', 'id', $context->instanceid)) {
+            if (!$cm = $DB->get_record('course_modules', array('id'=>$context->instanceid))) {
                 print_error('invalidmodule');
             }
-            if (!$course = get_record('course', 'id', $cm->course)) {
+            if (!$course = $DB->get_record('course', array('id'=>$cm->course))) {
                 print_error('invalidcourseid');
             }
             require_course_login($course, true, $cm);
@@ -931,7 +936,7 @@
  */
 function get_user_courses_bycap($userid, $cap, $accessdata, $doanything, $sort='c.sortorder ASC', $fields=NULL, $limit=0) {
 
-    global $CFG;
+    global $CFG, $DB;
 
     // Slim base fields, let callers ask for what they need...
     $basefields = array('id', 'sortorder', 'shortname', 'idnumber');
@@ -960,13 +965,13 @@
                        ctx.id AS ctxid, ctx.path AS ctxpath,
                        ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel,
                        cc.path AS categorypath
-                FROM {$CFG->prefix}course c
-                JOIN {$CFG->prefix}course_categories cc
-                  ON c.category=cc.id
-                JOIN {$CFG->prefix}context ctx 
-                  ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.")
-                $sort ";
-        $rs = get_recordset_sql($sql);
+                  FROM {course} c
+                  JOIN {course_categories} cc
+                       ON c.category=cc.id
+                  JOIN {context} ctx 
+                       ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.")
+                 $sort ";
+        $rs = $DB->get_recordset_sql($sql);
     } else {
         //
         // narrow down where we have the caps to a few contexts
@@ -975,23 +980,25 @@
         // - courses    where we have an explicit enrolment OR that have an override
         // 
         $sql = "SELECT ctx.*
-                FROM   {$CFG->prefix}context ctx
-                WHERE  ctx.contextlevel=".CONTEXT_COURSECAT."
-                ORDER BY ctx.depth";
-        $rs = get_recordset_sql($sql);
+                  FROM {context} ctx
+                 WHERE ctx.contextlevel=".CONTEXT_COURSECAT."
+              ORDER BY ctx.depth";
+        $rs = $DB->get_recordset_sql($sql);
         $catpaths = array();
-        while ($catctx = rs_fetch_next_record($rs)) {
+        foreach ($rs as $catctx) {
             if ($catctx->path != '' 
                 && has_capability_in_accessdata($cap, $catctx, $accessdata, $doanything)) {
                 $catpaths[] = $catctx->path;
             }
         }
-        rs_close($rs);
+        $rs->close();
         $catclause = '';
+        $catparams = array();
         if (count($catpaths)) {
             $cc = count($catpaths);
             for ($n=0;$n<$cc;$n++) {
-                $catpaths[$n] = "ctx.path LIKE '{$catpaths[$n]}/%'";
+                $catpaths[$n] = "ctx.path LIKE ?";
+                $params[] = "{$catpaths[$n]}/%";
             }
             $catclause = 'OR (' . implode(' OR ', $catpaths) .')';
         }
@@ -1010,35 +1017,40 @@
                        ctx.id AS ctxid, ctx.path AS ctxpath,
                        ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel,
                        cc.path AS categorypath
-                FROM {$CFG->prefix}course c
-                JOIN {$CFG->prefix}course_categories cc
-                  ON c.category=cc.id
-                JOIN {$CFG->prefix}context ctx 
-                  ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.")
-                LEFT OUTER JOIN {$CFG->prefix}role_assignments ra
-                  ON (ra.contextid=ctx.id AND ra.userid=$userid)
-                LEFT OUTER JOIN {$CFG->prefix}role_capabilities rc
-                  ON (rc.contextid=ctx.id AND (rc.capability='$cap' $capany))
-                WHERE    ra.id IS NOT NULL
-                      OR rc.id IS NOT NULL
-                      $catclause
+                  FROM {course} c
+                  JOIN {course_categories} cc
+                       ON c.category=cc.id
+                  JOIN {context} ctx 
+                       ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.")
+                  LEFT OUTER JOIN {role_assignments} ra
+                       ON (ra.contextid=ctx.id AND ra.userid=?)
+                  LEFT OUTER JOIN {role_capabilities} rc
+                       ON (rc.contextid=ctx.id AND (rc.capability=? $capany))
+                 WHERE ra.id IS NOT NULL
+                       OR rc.id IS NOT NULL
+                       $catclause
                 $sort ";
-        $rs = get_recordset_sql($sql);
+        $params = array($userid, $cap);
+        $params = array_merge($params, $catparams);
+        $rs = $DB->get_recordset_sql($sql, $params);
     }
     $courses = array();
     $cc = 0; // keep count
-    while ($c = rs_fetch_next_record($rs)) {
-        // build the context obj
-        $c = make_context_subobj($c);
-
-        if (has_capability_in_accessdata($cap, $c->context, $accessdata, $doanything)) {
-            $courses[] = $c;
-            if ($limit > 0 && $cc++ > $limit) {
-                break;
+    if ($rs) {
+        foreach ($rs as $c) {
+            // build the context obj
+            $c = make_context_subobj($c);
+
+            if (has_capability_in_accessdata($cap, $c->context, $accessdata, $doanything)) {
+                $courses[] = $c;
+                if ($limit > 0 && $cc++ > $limit) {
+                    break;
+                }
             }
         }
+        $rs->close();
     }
-    rs_close($rs);
+    
     return $courses;
 }
 
@@ -1060,7 +1072,7 @@
  */
 function get_user_access_sitewide($userid) {
 
-    global $CFG;
+    global $CFG, $DB;
 
     // this flag has not been set!
     // (not clean install, or upgraded successfully to 1.7 and up)
@@ -1089,14 +1101,15 @@
     // RAs
     //
     $sql = "SELECT ctx.path, ra.roleid, rc.capability, rc.permission
-            FROM {$CFG->prefix}role_assignments ra
-            JOIN {$CFG->prefix}context ctx
-               ON ra.contextid=ctx.id
-            LEFT OUTER JOIN {$CFG->prefix}role_capabilities rc
-               ON (rc.roleid=ra.roleid AND rc.contextid=ra.contextid)
-            WHERE ra.userid = $userid AND ctx.contextlevel <= ".CONTEXT_COURSE."
-            ORDER BY ctx.depth, ctx.path";
-    $rs = get_recordset_sql($sql);
+              FROM {role_assignments} ra
+              JOIN {context} ctx
+                   ON ra.contextid=ctx.id
+              LEFT OUTER JOIN {role_capabilities} rc
+                   ON (rc.roleid=ra.roleid AND rc.contextid=ra.contextid)
+             WHERE ra.userid = ? AND ctx.contextlevel <= ".CONTEXT_COURSE."
+          ORDER BY ctx.depth, ctx.path";
+    $params = array($userid);
+    $rs = $DB->get_recordset_sql($sql, $params);
     //
     // raparents collects paths & roles we need to walk up
     // the parenthood to build the rdef
@@ -1107,7 +1120,7 @@
     $raparents = array();
     $lastseen  = '';
     if ($rs) {
-        while ($ra = rs_fetch_next_record($rs)) {
+        foreach ($rs as $ra) {
             // RAs leafs are arrays to support multi
             // role assignments...
             if (!isset($accessdata['ra'][$ra->path])) {
@@ -1137,7 +1150,7 @@
             }
         }
         unset($ra);
-        rs_close($rs);
+        $rs->close();
     }
 
     // Walk up the tree to grab all the roledefs
@@ -1147,31 +1160,32 @@
     // categories... - extremely unlikely that the number of categories
     // and roletypes is so large that we hit the limits of IN()
     $clauses = array();
+    $cparams = array();
     foreach ($raparents as $roleid=>$contexts) {
         $contexts = implode(',', array_unique($contexts));
         if ($contexts ==! '') {
-            $clauses[] = "(roleid=$roleid AND contextid IN ($contexts))";
+            $clauses[] = "(roleid=? AND contextid IN ($contexts))";
+            $cparams[] = $roleid;
         }
     }
     $clauses = implode(" OR ", $clauses);
     if ($clauses !== '') {
         $sql = "SELECT ctx.path, rc.roleid, rc.capability, rc.permission
-                FROM {$CFG->prefix}role_capabilities rc
-                JOIN {$CFG->prefix}context ctx
+                FROM {role_capabilities} rc
+                JOIN {context} ctx
                   ON rc.contextid=ctx.id
                 WHERE $clauses
                 ORDER BY ctx.depth ASC, ctx.path DESC, rc.roleid ASC ";
-
-        $rs = get_recordset_sql($sql);
+        $rs = $DB->get_recordset_sql($sql, $params);
         unset($clauses);
 
         if ($rs) {
-            while ($rd = rs_fetch_next_record($rs)) {
+            foreach ($rs as $rd) {
                 $k = "{$rd->path}:{$rd->roleid}";
                 $accessdata['rdef'][$k][$rd->capability] = $rd->permission;
             }
             unset($rd);
-            rs_close($rs);
+            $rs->close();
         }
     }
 
@@ -1186,25 +1200,25 @@
     $sql = "SELECT sctx.path, ra.roleid,
                    ctx.path AS parentpath,
                    rco.capability, rco.permission
-            FROM {$CFG->prefix}role_assignments ra
-            JOIN {$CFG->prefix}context ctx
-              ON ra.contextid=ctx.id
-            JOIN {$CFG->prefix}context sctx
-              ON (sctx.path LIKE " . sql_concat('ctx.path',"'/%'"). " )
-            JOIN {$CFG->prefix}role_capabilities rco
-              ON (rco.roleid=ra.roleid AND rco.contextid=sctx.id)
-            WHERE ra.userid = $userid
-                  AND sctx.contextlevel <= ".CONTEXT_COURSE."
-            ORDER BY sctx.depth, sctx.path, ra.roleid";
-
-    $rs = get_recordset_sql($sql);
+              FROM {role_assignments} ra
+              JOIN {context} ctx
+                   ON ra.contextid=ctx.id
+              JOIN {context} sctx
+                   ON (sctx.path LIKE " . sql_concat('ctx.path',"'/%'"). " )
+              JOIN {role_capabilities} rco
+                   ON (rco.roleid=ra.roleid AND rco.contextid=sctx.id)
+             WHERE ra.userid = ?
+                   AND sctx.contextlevel <= ".CONTEXT_COURSE."
+          ORDER BY sctx.depth, sctx.path, ra.roleid";
+    $params = array($userid);
+    $rs = $DB->get_recordset_sql($sql, $params);
     if ($rs) {
-        while ($rd = rs_fetch_next_record($rs)) {
+        foreach ($rs as $rd) {
             $k = "{$rd->path}:{$rd->roleid}";
             $accessdata['rdef'][$k][$rd->capability] = $rd->permission;
         }
         unset($rd);
-        rs_close($rs);
+        $rs->close();
     }
     return $accessdata;
 }
@@ -1219,9 +1233,7 @@
  */
 function load_subcontext($userid, $context, &$accessdata) {
 
-    global $CFG;
-
-
+    global $CFG, $DB;
 
     /* Get the additional RAs and relevant rolecaps
      * - role assignments - with role_caps
@@ -1262,26 +1274,29 @@
     // Role assignments in the context and below
     //
     $sql = "SELECT ctx.path, ra.roleid
-            FROM {$CFG->prefix}role_assignments ra
-            JOIN {$CFG->prefix}context ctx
-               ON ra.contextid=ctx.id
-            WHERE ra.userid = $userid
-                  AND (ctx.path = '{$context->path}' OR ctx.path LIKE '{$context->path}/%')
-            ORDER BY ctx.depth, ctx.path";
-    $rs = get_recordset_sql($sql);
+              FROM {role_assignments} ra
+              JOIN {context} ctx
+                   ON ra.contextid=ctx.id
+             WHERE ra.userid = ?
+                   AND (ctx.path = ? OR ctx.path LIKE ?)
+          ORDER BY ctx.depth, ctx.path";
+    $params = array($userid, $context->path, $context->path."/%");
+    $rs = $DB->get_recordset_sql($sql, $params);
 
     // 
     // Read in the RAs
     //
-    $localroles = array();
-    while ($ra = rs_fetch_next_record($rs)) {
-        if (!isset($accessdata['ra'][$ra->path])) {
-            $accessdata['ra'][$ra->path] = array();
+    if ($rs) {
+        $localroles = array();
+        foreach ($rs as $ra) {
+            if (!isset($accessdata['ra'][$ra->path])) {
+                $accessdata['ra'][$ra->path] = array();
+            }
+            array_push($accessdata['ra'][$ra->path], $ra->roleid);
+            array_push($localroles,           $ra->roleid);
         }
-        array_push($accessdata['ra'][$ra->path], $ra->roleid);
-        array_push($localroles,           $ra->roleid);
+        $rs->close();
     }
-    rs_close($rs);
 
     //
     // Walk up and down the tree to grab all the roledefs
@@ -1310,24 +1325,25 @@
         $whereroles = "rc.roleid IN ($roleids) AND";
     }
     $sql = "SELECT ctx.path, rc.roleid, rc.capability, rc.permission
-            FROM {$CFG->prefix}role_capabilities rc
-            JOIN {$CFG->prefix}context ctx
-             ON rc.contextid=ctx.id
-            WHERE ($whereroles
-                    (ctx.id={$context->id} OR ctx.path LIKE '{$context->path}/%'))
-                    $wherelocalroles
-            ORDER BY ctx.depth ASC, ctx.path DESC, rc.roleid ASC ";
+              FROM {role_capabilities} rc
+              JOIN {context} ctx
+                   ON rc.contextid=ctx.id
+             WHERE ($whereroles
+                    (ctx.id=? OR ctx.path LIKE ?))
+                   $wherelocalroles
+          ORDER BY ctx.depth ASC, ctx.path DESC, rc.roleid ASC ";
+    $params = array($context->id, $context->path."/%");
 
     $newrdefs = array();
-    if ($rs = get_recordset_sql($sql)) {
-        while ($rd = rs_fetch_next_record($rs)) {
+    if ($rs = $DB->get_recordset_sql($sql, $params)) {
+        foreach ($rs as $rd) {
             $k = "{$rd->path}:{$rd->roleid}";
             if (!array_key_exists($k, $newrdefs)) {
                 $newrdefs[$k] = array();
             }
             $newrdefs[$k][$rd->capability] = $rd->permission;
         }
-        rs_close($rs);
+        $rs->close();
     } else {
         debugging('Bad SQL encountered!');
     }
@@ -1358,7 +1374,7 @@
  */
 function get_role_access_bycontext($roleid, $context, $accessdata=NULL) {
 
-    global $CFG;
+    global $CFG, $DB;
 
     /* Get the relevant rolecaps into rdef
      * - relevant role caps
@@ -1386,20 +1402,22 @@
     // categories is so large that we hit the limits of IN()
     //
     $sql = "SELECT ctx.path, rc.capability, rc.permission
-            FROM {$CFG->prefix}role_capabilities rc
-            JOIN {$CFG->prefix}context ctx
-              ON rc.contextid=ctx.id
-            WHERE rc.roleid=$roleid AND
-                  ( ctx.id IN ($contexts) OR 
-                    ctx.path LIKE '{$context->path}/%' )
-            ORDER BY ctx.depth ASC, ctx.path DESC, rc.roleid ASC ";
+              FROM {role_capabilities} rc
+              JOIN {context} ctx
+                   ON rc.contextid=ctx.id
+             WHERE rc.roleid=? AND
+                   ( ctx.id IN ($contexts) OR 
+                    ctx.path LIKE ? )
+          ORDER BY ctx.depth ASC, ctx.path DESC, rc.roleid ASC ";
+    $params = array($roleid, $context->path."/%");
 
-    $rs = get_recordset_sql($sql);
-    while ($rd = rs_fetch_next_record($rs)) {
-        $k = "{$rd->path}:{$roleid}";
-        $accessdata['rdef'][$k][$rd->capability] = $rd->permission;
+    if ($rs = $DB->get_recordset_sql($sql, $params)) {
+        foreach ($rs as $rd) {
+            $k = "{$rd->path}:{$roleid}";
+            $accessdata['rdef'][$k][$rd->capability] = $rd->permission;
+        }
+        $rs->close();
     }
-    rs_close($rs);
 
     return $accessdata;
 }
@@ -1553,7 +1571,7 @@
  *
  */
 function reload_all_capabilities() {
-    global $USER,$CFG;
+    global $USER, $DB;
 
     // error_log("reloading");
     // copy switchroles
@@ -1569,13 +1587,13 @@
     load_all_capabilities();
 
     foreach ($sw as $path => $roleid) {
-        $context = get_record('context', 'path', $path);
+        $context = $DB->get_record('context', array('path'=>$path));
         role_switch($roleid, $context);
     }
 
 }
 
-/*
+/**
  * Adds a temp role to an accessdata array.
  *
  * Useful for the "temporary guest" access
@@ -1586,7 +1604,7 @@
  */
 function load_temp_role($context, $roleid, $accessdata) {
 
-    global $CFG;
+    global $CFG, $DB;
 
     //
     // Load rdefs for the role in -
@@ -1599,21 +1617,22 @@
     $contexts = substr($context->path, 1); // kill leading slash
     $contexts = str_replace('/', ',', $contexts);
 
-    $sql = "SELECT ctx.path,
-                   rc.capability, rc.permission
-            FROM {$CFG->prefix}context ctx
-            JOIN {$CFG->prefix}role_capabilities rc
-              ON rc.contextid=ctx.id
-            WHERE (ctx.id IN ($contexts)
-                   OR ctx.path LIKE '{$context->path}/%')
-                  AND rc.roleid = {$roleid}
-            ORDER BY ctx.depth, ctx.path";
-    $rs = get_recordset_sql($sql);
-    while ($rd = rs_fetch_next_record($rs)) {
-        $k = "{$rd->path}:{$roleid}";
-        $accessdata['rdef'][$k][$rd->capability] = $rd->permission;
+    $sql = "SELECT ctx.path, rc.capability, rc.permission
+              FROM {context} ctx
+              JOIN {role_capabilities} rc
+                   ON rc.contextid=ctx.id
+             WHERE (ctx.id IN ($contexts)
+                    OR ctx.path LIKE ?)
+                   AND rc.roleid = ?
+          ORDER BY ctx.depth, ctx.path";
+    $params = array($context->path."/%", $roleid); 
+    if ($rs = get_recordset_sql($sql, $params)) {
+        foreach ($rs as $rd) {
+            $k = "{$rd->path}:{$roleid}";
+            $accessdata['rdef'][$k][$rd->capability] = $rd->permission;
+        }
+        $rs-close();
     }
-    rs_close($rs);
 
     //
     // Say we loaded everything for the course context
@@ -1681,34 +1700,30 @@
 
 /**
  * Installs the roles system.
- * This function runs on a fresh install as well as on an upgrade from the old
- * hard-coded student/teacher/admin etc. roles to the new roles system.
+ * This function runs on a fresh install only now
  */
 function moodle_install_roles() {
-
-    global $CFG, $db;
-
+    global $DB;
 /// Create a system wide context for assignemnt.
     $systemcontext = $context = get_context_instance(CONTEXT_SYSTEM);
 
-
 /// Create default/legacy roles and capabilities.
 /// (1 legacy capability per legacy role at system level).
 
-    $adminrole          = create_role(addslashes(get_string('administrator')), 'admin',
-                                      addslashes(get_string('administratordescription')), 'moodle/legacy:admin');
-    $coursecreatorrole  = create_role(addslashes(get_string('coursecreators')), 'coursecreator',
-                                      addslashes(get_string('coursecreatorsdescription')), 'moodle/legacy:coursecreator');
-    $editteacherrole    = create_role(addslashes(get_string('defaultcourseteacher')), 'editingteacher',
-                                      addslashes(get_string('defaultcourseteacherdescription')), 'moodle/legacy:editingteacher');
-    $noneditteacherrole = create_role(addslashes(get_string('noneditingteacher')), 'teacher',
-                                      addslashes(get_string('noneditingteacherdescription')), 'moodle/legacy:teacher');
-    $studentrole        = create_role(addslashes(get_string('defaultcoursestudent')), 'student',
-                                      addslashes(get_string('defaultcoursestudentdescription')), 'moodle/legacy:student');
-    $guestrole          = create_role(addslashes(get_string('guest')), 'guest',
-                                      addslashes(get_string('guestdescription')), 'moodle/legacy:guest');
-    $userrole           = create_role(addslashes(get_string('authenticateduser')), 'user',
-                                      addslashes(get_string('authenticateduserdescription')), 'moodle/legacy:user');
+    $adminrole          = create_role(get_string('administrator'), 'admin',
+                                      get_string('administratordescription'), 'moodle/legacy:admin');
+    $coursecreatorrole  = create_role(get_string('coursecreators'), 'coursecreator',
+                                      get_string('coursecreatorsdescription'), 'moodle/legacy:coursecreator');
+    $editteacherrole    = create_role(get_string('defaultcourseteacher'), 'editingteacher',
+                                      get_string('defaultcourseteacherdescription'), 'moodle/legacy:editingteacher');
+    $noneditteacherrole = create_role(get_string('noneditingteacher'), 'teacher',
+                                      get_string('noneditingteacherdescription'), 'moodle/legacy:teacher');
+    $studentrole        = create_role(get_string('defaultcoursestudent'), 'student',
+                                      get_string('defaultcoursestudentdescription'), 'moodle/legacy:student');
+    $guestrole          = create_role(get_string('guest'), 'guest',
+                                      get_string('guestdescription'), 'moodle/legacy:guest');
+    $userrole           = create_role(get_string('authenticateduser'), 'user',
+                                      get_string('authenticateduserdescription'), 'moodle/legacy:user');
 
 /// Now is the correct moment to install capabilities - after creation of legacy roles, but before assigning of roles
 
@@ -1719,121 +1734,10 @@
         print_error('cannotupgradecaps');
     }
 
-/// Look inside user_admin, user_creator, user_teachers, user_students and
-/// assign above new roles. If a user has both teacher and student role,
-/// only teacher role is assigned. The assignment should be system level.
-
-    $dbtables = $db->MetaTables('TABLES');
-
-/// Set up the progress bar
-
-    $usertables = array('user_admins', 'user_coursecreators', 'user_teachers', 'user_students');
-
-    $totalcount = $progresscount = 0;
-    foreach ($usertables as $usertable) {
-        if (in_array($CFG->prefix.$usertable, $dbtables)) {
-             $totalcount += count_records($usertable);
-        }
-    }
-
-    print_progress(0, $totalcount, 5, 1, 'Processing role assignments');
-
-/// Upgrade the admins.
-/// Sort using id ASC, first one is primary admin.
-
-    if (in_array($CFG->prefix.'user_admins', $dbtables)) {
-        if ($rs = get_recordset_sql('SELECT * from '.$CFG->prefix.'user_admins ORDER BY ID ASC')) {
-            while ($admin = rs_fetch_next_record($rs)) {
-                role_assign($adminrole, $admin->userid, 0, $systemcontext->id);
-                $progresscount++;
-                print_progress($progresscount, $totalcount, 5, 1, 'Processing role assignments');
-            }
-            rs_close($rs);
-        }
-    } else {
-        // This is a fresh install.
-    }
-
-
-/// Upgrade course creators.
-    if (in_array($CFG->prefix.'user_coursecreators', $dbtables)) {
-        if ($rs = get_recordset('user_coursecreators')) {
-            while ($coursecreator = rs_fetch_next_record($rs)) {
-                role_assign($coursecreatorrole, $coursecreator->userid, 0, $systemcontext->id);
-                $progresscount++;
-                print_progress($progresscount, $totalcount, 5, 1, 'Processing role assignments');
-            }
-            rs_close($rs);
-        }
-    }
-
-
-/// Upgrade editting teachers and non-editting teachers.
-    if (in_array($CFG->prefix.'user_teachers', $dbtables)) {
-        if ($rs = get_recordset('user_teachers')) {
-            while ($teacher = rs_fetch_next_record($rs)) {
-
-                // removed code here to ignore site level assignments
-                // since the contexts are separated now
-
-                // populate the user_lastaccess table
-                $access = new object();
-                $access->timeaccess = $teacher->timeaccess;
-                $access->userid = $teacher->userid;
-                $access->courseid = $teacher->course;
-                insert_record('user_lastaccess', $access);
-
-                // assign the default student role
-                $coursecontext = get_context_instance(CONTEXT_COURSE, $teacher->course); // needs cache
-                // hidden teacher
-                if ($teacher->authority == 0) {
-                    $hiddenteacher = 1;
-                } else {
-                    $hiddenteacher = 0;
-                }
-
-                if ($teacher->editall) { // editting teacher
-                    role_assign($editteacherrole, $teacher->userid, 0, $coursecontext->id, $teacher->timestart, $teacher->timeend, $hiddenteacher, $teacher->enrol, $teacher->timemodified);
-                } else {
-                    role_assign($noneditteacherrole, $teacher->userid, 0, $coursecontext->id, $teacher->timestart, $teacher->timeend, $hiddenteacher, $teacher->enrol, $teacher->timemodified);
-                }
-                $progresscount++;
-                print_progress($progresscount, $totalcount, 5, 1, 'Processing role assignments');
-            }
-            rs_close($rs);
-        }
-    }
-
-
-/// Upgrade students.
-    if (in_array($CFG->prefix.'user_students', $dbtables)) {
-        if ($rs = get_recordset('user_students')) {
-            while ($student = rs_fetch_next_record($rs)) {
-
-                // populate the user_lastaccess table
-                $access = new object;
-                $access->timeaccess = $student->timeaccess;
-                $access->userid = $student->userid;
-                $access->courseid = $student->course;
-                insert_record('user_lastaccess', $access);
-
-                // assign the default student role
-                $coursecontext = get_context_instance(CONTEXT_COURSE, $student->course);
-                role_assign($studentrole, $student->userid, 0, $coursecontext->id, $student->timestart, $student->timeend, 0, $student->enrol, $student->time);
-                $progresscount++;
-                print_progress($progresscount, $totalcount, 5, 1, 'Processing role assignments');
-            }
-            rs_close($rs);
-        }
-    }
-
-
 /// Upgrade guest (only 1 entry).
-    if ($guestuser = get_record('user', 'username', 'guest')) {
+    if ($guestuser = $DB->get_record('user', array('username'=>'guest'))) {
         role_assign($guestrole, $guestuser->id, 0, $systemcontext->id);
     }
-    print_progress($totalcount, $totalcount, 5, 1, 'Processing role assignments');
-
 
 /// Insert the correct records for legacy roles
     allow_assign($adminrole, $adminrole);
@@ -1860,17 +1764,6 @@
     allow_override($adminrole, $studentrole);
     allow_override($adminrole, $guestrole);
     allow_override($adminrole, $userrole);
-
-
-/// Delete the old user tables when we are done
-
-    $tables = array('user_students', 'user_teachers', 'user_coursecreators', 'user_admins');  
-    foreach ($tables as $tablename) {
-        $table = new XMLDBTable($tablename);
-        if (table_exists($table)) {
-            drop_table($table);
-        }
-    }
 }
 
 /**
@@ -2510,14 +2403,15 @@
  * @return id or false
  */
 function create_role($name, $shortname, $description, $legacy='') {
+    global $DB;
 
     // check for duplicate role name
 
-    if ($role = get_record('role','name', $name)) {
+    if ($role = $DB->get_record('role', array('name'=>$name))) {
         print_error('duplicaterolename');
     }
 
-    if ($role = get_record('role','shortname', $shortname)) {
+    if ($role = $DB->get_record('role', array('shortname'=>$shortname))) {
         print_error('duplicateroleshortname');
     }
 
@@ -2527,8 +2421,8 @@
     $role->description = $description;
 
     //find free sortorder number
-    $role->sortorder = count_records('role');
-    while (get_record('role','sortorder', $role->sortorder)) {
+    $role->sortorder = $DB->count_records('role');
+    while ($DB->get_record('role',array('sortorder'=>$role->sortorder))) {
         $role->sortorder += 1;
     }
 
@@ -2536,7 +2430,7 @@
         return false;
     }
 
-    if ($id = insert_record('role', $role)) {
+    if ($id = $DB->insert_record('role', $role)) {
         if ($legacy) {
             assign_capability($legacy, CAP_ALLOW, $id, $context->id);
         }
@@ -2567,7 +2461,7 @@
  * @return success
  */
 function delete_role($roleid) {
-    global $CFG;
+    global $CFG, $DB;
     $success = true;
 
 // mdl 10149, check if this is the last active admin role
@@ -2575,15 +2469,15 @@
 
     $systemcontext = get_context_instance(CONTEXT_SYSTEM);
 
-    if ($role = get_record('role', 'id', $roleid)) {
-        if (record_exists('role_capabilities', 'contextid', $systemcontext->id, 'roleid', $roleid, 'capability', 'moodle/site:doanything')) {
+    if ($role = $DB->get_record('role', array('id'=>$roleid))) {
+        if ($DB->record_exists('role_capabilities', array('contextid'=>$systemcontext->id, 'roleid'=>$roleid, 'capability'=>'moodle/site:doanything'))) {
             // deleting an admin role
             $status = false;
             if ($adminroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $systemcontext)) {
                 foreach ($adminroles as $adminrole) {
                     if ($adminrole->id != $roleid) {
                         // some other admin role
-                        if (record_exists('role_assignments', 'roleid', $adminrole->id, 'contextid', $systemcontext->id)) {
+                        if ($DB->record_exists('role_assignments', array('roleid'=>$adminrole->id, 'contextid'=>$systemcontext->id))) {
                             // found another admin role with at least 1 user assigned
                             $status = true;
                             break;
@@ -2611,20 +2505,20 @@
                                      FROM {$CFG->prefix}role_capabilities
                                      WHERE roleid = $roleid");
 
-        delete_records('role_capabilities', 'roleid', $roleid);
+        $DB->delete_records('role_capabilities', array('roleid'=>$roleid));
 
-        delete_records('role_allow_assign', 'roleid', $roleid);
-        delete_records('role_allow_assign', 'allowassign', $roleid);
-        delete_records('role_allow_override', 'roleid', $roleid);
-        delete_records('role_allow_override', 'allowoverride', $roleid);
-        delete_records('role_names', 'roleid', $roleid);
+        $DB->delete_records('role_allow_assign', array('roleid'=>$roleid));
+        $DB->delete_records('role_allow_assign', array('allowassign'=>$roleid));
+        $DB->delete_records('role_allow_override', array('roleid'=>$roleid));
+        $DB->delete_records('role_allow_override', array('allowoverride'=>$roleid));
+        $DB->delete_records('role_names', array('roleid'=>$roleid));
     }
 
 // finally delete the role itself
     // get this before the name is gone for logging
-    $rolename = get_field('role', 'name', 'id', $roleid);
+    $rolename = $DB->get_field('role', 'name', array('id'=>$roleid));
     
-    if ($success and !delete_records('role', 'id', $roleid)) {
+    if ($success and !$DB->delete_records('role', array('id'=>$roleid))) {
         debugging("Could not delete role record with ID $roleid!");
         $success = false;
     }
@@ -2647,14 +2541,14 @@
  */
 function assign_capability($capability, $permission, $roleid, $contextid, $overwrite=false) {
 
-    global $USER;
+    global $USER, $DB;
 
     if (empty($permission) || $permission == CAP_INHERIT) { // if permission is not set
         unassign_capability($capability, $roleid, $contextid);
         return true;
     }
 
-    $existing = get_record('role_capabilities', 'contextid', $contextid, 'roleid', $roleid, 'capability', $capability);
+    $existing = $DB->get_record('role_capabilities', array('contextid'=>$contextid, 'roleid'=>$roleid, 'capability'=>$capability));
 
     if ($existing and !$overwrite) {   // We want to keep whatever is there already
         return true;
@@ -2670,10 +2564,10 @@
 
     if ($existing) {
         $cap->id = $existing->id;
-        return update_record('role_capabilities', $cap);
+        return $DB->update_record('role_capabilities', $cap);
     } else {
-        $c = get_record('context', 'id', $contextid);
-        return insert_record('role_capabilities', $cap);
+        $c = $DB->get_record('context', array('id'=>$contextid));
+        return $DB->insert_record('role_capabilities', $cap);
     }
 }
 
@@ -2684,14 +2578,15 @@
  * @return boolean - success or failure
  */
 function unassign_capability($capability, $roleid, $contextid=NULL) {
+    global $DB;
 
     if (isset($contextid)) {
         // delete from context rel, if this is the last override in this context
-        $status = delete_records('role_capabilities', 'capability', $capability,
-                'roleid', $roleid, 'contextid', $contextid);
+        $status = $DB->delete_records('role_capabilities', array('capability'=>$capability,
+                'roleid'=>$roleid, 'contextid'=>$contextid));
     } else {
-        $status = delete_records('role_capabilities', 'capability', $capability,
-                'roleid', $roleid);
+        $status = $DB->delete_records('role_capabilities', array('capability'=>$capability,
+                'roleid'=>$roleid));
     }
     return $status;
 }
@@ -2708,8 +2603,10 @@
  */
 function get_roles_with_capability($capability, $permission=NULL, $context='') {
 
-    global $CFG;
+    global $CFG, $DB;
 
+    $params = array();
+    
     if ($context) {
         if ($contexts = get_parent_contexts($context)) {
             $listofcontexts = '('.implode(',', $contexts).')';
@@ -2717,7 +2614,8 @@
             $sitecontext = get_context_instance(CONTEXT_SYSTEM);
             $listofcontexts = '('.$sitecontext->id.')'; // must be site
         }
-        $contextstr = "AND (rc.contextid = '$context->id' OR  rc.contextid IN $listofcontexts)";
+        $contextstr = "AND (rc.contextid = ? OR  rc.contextid IN $listofcontexts)";
+        $params[] = $context->id;
     } else {
         $contextstr = '';
     }
@@ -2725,13 +2623,16 @@
     $selectroles = "SELECT r.*
                       FROM {$CFG->prefix}role r,
                            {$CFG->prefix}role_capabilities rc
-                     WHERE rc.capability = '$capability'
+                     WHERE rc.capability = ?
                        AND rc.roleid = r.id $contextstr";
 
+    array_unshift($params, $capability);
+
     if (isset($permission)) {
-        $selectroles .= " AND rc.permission = '$permission'";
+        $selectroles .= " AND rc.permission = ?";
+        $params[] = $permission;
     }
-    return get_records_sql($selectroles);
+    return $DB->get_records_sql($selectroles, $params);
 }
 
 
@@ -2747,7 +2648,7 @@
  * @return id - new id of the assigment
  */
 function role_assign($roleid, $userid, $groupid, $contextid, $timestart=0, $timeend=0, $hidden=0, $enrol='manual',$timemodified='') {
-    global $USER, $CFG;
+    global $USER, $CFG, $DB;
 
 /// Do some data validation
 
@@ -2787,9 +2688,9 @@
 
 /// Check for existing entry
     if ($userid) {
-        $ra = get_record('role_assignments', 'roleid', $roleid, 'contextid', $context->id, 'userid', $userid);
+        $ra = $DB->get_record('role_assignments', array('roleid'=>$roleid, 'contextid'=>$context->id, 'userid'=>$userid));
     } else {
-        $ra = get_record('role_assignments', 'roleid', $roleid, 'contextid', $context->id, 'groupid', $groupid);
+        $ra = $DB->get_record('role_assignments', array('roleid'=>$roleid, 'contextid'=>$context->id, 'groupid'=>$groupid));
     }
 
 
@@ -2808,7 +2709,7 @@
         $newra->timemodified = $timemodified;
         $newra->modifierid = empty($USER->id) ? 0 : $USER->id;
 
-        $success = insert_record('role_assignments', $newra);
+        $success = $DB->insert_record('role_assignments', $newra);
 
     } else {                      // We already have one, just update it
 
@@ -2822,7 +2723,7 @@
         $newra->timemodified = $timemodified;
         $newra->modifierid = empty($USER->id) ? 0 : $USER->id;
 
-        $success = update_record('role_assignments', $newra);
+        $success = $DB->update_record('role_assignments', $newra);
     }
 
     if ($success) {   /// Role was assigned, so do some other things
@@ -2850,7 +2751,7 @@
 
     /// now handle metacourse role assignments if in course context
     if ($success and $context->contextlevel == CONTEXT_COURSE) {
-        if ($parents = get_records('course_meta', 'child_course', $context->instanceid)) {
+        if ($parents = $DB->get_records('course_meta', array('child_course'=>$context->instanceid))) {
             foreach ($parents as $parent) {
                 sync_metacourse($parent->parent_course);
             }
Index: lib/grouplib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/grouplib.php,v
retrieving revision 1.30
diff -u -r1.30 grouplib.php
--- lib/grouplib.php	13 Apr 2008 21:59:27 -0000	1.30
+++ lib/grouplib.php	15 May 2008 21:11:02 -0000
@@ -23,7 +23,8 @@
  * occurred.
  */
 function groups_group_exists($groupid) {
-    return record_exists('groups', 'id', $groupid);
+    global $DB;
+    return $DB->record_exists('groups', array('id'=>$groupid));
 }
 
 /**
@@ -32,7 +33,8 @@
  * @return string The name of the group
  */
 function groups_get_group_name($groupid) {
-    return get_field('groups', 'name', 'id', $groupid);
+    global $DB;
+    return $DB->get_field('groups', 'name', array('id'=>$groupid));
 }
 
 /**
@@ -41,7 +43,8 @@
  * @return string The name of the grouping
  */
 function groups_get_grouping_name($groupingid) {
-    return get_field('groupings', 'name', 'id', $groupingid);
+    global $DB;
+    return $DB->get_field('groupings', 'name', array('id'=>$groupingid));
 }
 
 /**
@@ -52,7 +55,8 @@
  * @return int $groupid
  */
 function groups_get_group_by_name($courseid, $name) {
-    if ($groups = get_records_select('groups', "courseid=$courseid AND name='".addslashes($name)."'")) {
+    global $DB;
+    if ($groups = $DB->get_records('groups', array('courseid'=>$courseid, 'name'=>$name))) {
         return key($groups);
     }
     return false;
@@ -66,7 +70,8 @@
  * @return int $groupid
  */
 function groups_get_grouping_by_name($courseid, $name) {
-    if ($groupings = get_records_select('groupings', "courseid=$courseid AND name='".addslashes($name)."'")) {
+    global $DB;
+    if ($groupings = $DB->get_records_select('groupings', array('courseid'=>$courseid, 'name'=>$name))) {
         return key($groupings);
     }
     return false;
@@ -78,7 +83,8 @@
  * @return group object
  */
 function groups_get_group($groupid) {
-    return get_record('groups', 'id', $groupid);
+    global $DB;
+    return $DB->get_record('groups', array('id'=>$groupid));
 }
 
 /**
@@ -87,7 +93,8 @@
  * @return group object
  */
 function groups_get_grouping($groupingid) {
-    return get_record('groupings', 'id', $groupingid);
+    global $DB;
+    return $DB->get_record('groupings', array('id'=>$groupingid));
 }
 
 /**
@@ -99,39 +106,40 @@
  * or an error occurred. (userid field returned if array in $userid)
  */
 function groups_get_all_groups($courseid, $userid=0, $groupingid=0, $fields='g.*') {
-    global $CFG;
+    global $CFG, $DB;
 
     // groupings are ignored when not enabled
     if (empty($CFG->enablegroupings)) {
         $groupingid = 0;
     }
 
+
     if (empty($userid)) {
         $userfrom  = "";
         $userwhere = "";
-
-    } else if (is_array($userid)) {
-        $userids = implode(',', $userid);
-        $userfrom  = ", {$CFG->prefix}groups_members gm";
-        $userwhere = "AND g.id = gm.groupid AND gm.userid IN ($userids)";
+        $params = array();
 
     } else {
-        $userfrom  = ", {$CFG->prefix}groups_members gm";
-        $userwhere = "AND g.id = gm.groupid AND gm.userid = '$userid'";
+        list($usql, $params) = $DB->get_in_or_equal($userid);
+        $userfrom  = ", {groups_members} gm";
+        $userwhere = "AND g.id = gm.groupid AND gm.userid $usql";
     }
 
     if (!empty($groupingid)) {
-        $groupingfrom  = ", {$CFG->prefix}groupings_groups gg";
-        $groupingwhere = "AND g.id = gg.groupid AND gg.groupingid = '$groupingid'";
+        $groupingfrom  = ", {groupings_groups} gg";
+        $groupingwhere = "AND g.id = gg.groupid AND gg.groupingid = ?";
+        $params[] = $groupingid;
     } else {
         $groupingfrom  = "";
         $groupingwhere = "";
     }
 
-    return get_records_sql("SELECT $fields
-                              FROM {$CFG->prefix}groups g $userfrom $groupingfrom
-                             WHERE g.courseid = $courseid $userwhere $groupingwhere
-                          ORDER BY name ASC");
+    array_unshift($params, $courseid);
+
+    return $DB->get_records_sql("SELECT $fields
+                                   FROM {groups} g $userfrom $groupingfrom
+                                  WHERE g.courseid = ? $userwhere $groupingwhere
+                               ORDER BY name ASC", $params);
 }
 
 /**
@@ -141,24 +149,27 @@
  * @return array[groupingid][groupid] including grouping id 0 which means all groups
  */
 function groups_get_user_groups($courseid, $userid=0) {
-    global $CFG, $USER;
+    global $CFG, $USER, $DB;
 
     if (empty($userid)) {
         $userid = $USER->id;
     }
 
-    if (!$rs = get_recordset_sql("SELECT g.id, gg.groupingid
-                                    FROM {$CFG->prefix}groups g
-                                         JOIN {$CFG->prefix}groups_members gm        ON gm.groupid = g.id
-                                         LEFT JOIN {$CFG->prefix}groupings_groups gg ON gg.groupid = g.id
-                                   WHERE gm.userid = $userid AND g.courseid = $courseid")) {
+    $sql = "SELECT g.id, gg.groupingid
+              FROM {groups} g
+                   JOIN {groups_members} gm   ON gm.groupid = g.id
+              LEFT JOIN {groupings_groups} gg ON gg.groupid = g.id
+             WHERE gm.userid = ? AND g.courseid = ?";
+    $params = array($userid, $courseid);
+
+    if (!$rs = $DB->get_recordset_sql($sql, $params)) {
         return array('0' => array());
     }
 
     $result    = array();
     $allgroups = array();
     
-    while ($group = rs_fetch_next_record($rs)) {
+    foreach ($rs as $group) {
         $allgroups[$group->id] = $group->id;
         if (is_null($group->groupingid)) {
             continue;
@@ -168,7 +179,7 @@
         }
         $result[$group->groupingid][$group->id] = $group->id;
     }
-    rs_close($rs);
+    $rs->close();
 
     $result['0'] = array_keys($allgroups); // all groups
 
@@ -182,16 +193,16 @@
  * or an error occurred.
  */
 function groups_get_all_groupings($courseid) {
-    global $CFG;
+    global $CFG, $DB;
 
     // groupings are ignored when not enabled
     if (empty($CFG->enablegroupings)) {
         return(false);
     }
-    return get_records_sql("SELECT *
-                              FROM {$CFG->prefix}groupings
-                             WHERE courseid = $courseid
-                          ORDER BY name ASC");
+    return $DB->get_records_sql("SELECT *
+                                   FROM {groupings}
+                                  WHERE courseid = ?
+                               ORDER BY name ASC", array($courseid));
 }
 
 
@@ -205,13 +216,13 @@
  * @return boolean True if the user is a member, false otherwise.
  */
 function groups_is_member($groupid, $userid=null) {
-    global $USER;
+    global $USER, $DB;
 
     if (!$userid) {
         $userid = $USER->id;
     }
 
-    return record_exists('groups_members', 'groupid', $groupid, 'userid', $userid);
+    return $DB->record_exists('groups_members', array('groupid'=>$groupid, 'userid'=>$userid));
 }
 
 /**
@@ -221,7 +232,7 @@
  * @return booelan true if user member of at least one group used in activity
  */
 function groups_has_membership($cm, $userid=null) {
-    global $CFG, $USER;
+    global $CFG, $USER, $DB;
 
     static $cache = array();
 
@@ -242,17 +253,19 @@
     if ($cm->groupingid) {
         // find out if member of any group in selected activity grouping
         $sql = "SELECT 'x'
-                  FROM {$CFG->prefix}groups_members gm, {$CFG->prefix}groupings_groups gg
-                 WHERE gm.userid = $userid AND gm.groupid = gg.groupid AND gg.groupingid = {$cm->groupingid}";
+                  FROM {groups_members} gm, {groupings_groups} gg
+                 WHERE gm.userid = ? AND gm.groupid = gg.groupid AND gg.groupingid = ?";
+        $params = array($userid, $cm->groupingid);
 
     } else {
         // no grouping used - check all groups in course
         $sql = "SELECT 'x'
-                  FROM {$CFG->prefix}groups_members gm, {$CFG->prefix}groups g
-                 WHERE gm.userid = $userid AND gm.groupid = g.id AND g.courseid = {$cm->course}";
+                  FROM {groups_members} gm, {groups} g
+                 WHERE gm.userid = ? AND gm.groupid = g.id AND g.courseid = ?";
+        $params = array($userid, $cm->course);
     }
 
-    $cache[$cachekey] = record_exists_sql($sql);
+    $cache[$cachekey] = $DB->record_exists_sql($sql, $params);
 
     return $cache[$cachekey];
 }
@@ -266,12 +279,12 @@
  * group or false if no users or an error returned.
  */
 function groups_get_members($groupid, $fields='u.*', $sort='lastname ASC') {
-    global $CFG;
+    global $DB;
 
-    return get_records_sql("SELECT $fields
-                              FROM {$CFG->prefix}user u, {$CFG->prefix}groups_members gm
-                             WHERE u.id = gm.userid AND gm.groupid = '$groupid'
-                          ORDER BY $sort");
+    return $DB->get_records_sql("SELECT $fields
+                                   FROM {user} u, {groups_members} gm
+                                  WHERE u.id = gm.userid AND gm.groupid = ?
+                               ORDER BY $sort", array($groupid));
 }
 
 
@@ -284,14 +297,14 @@
  * group or false if no users or an error returned.
  */
 function groups_get_grouping_members($groupingid, $fields='u.*', $sort='lastname ASC') {
-    global $CFG;
+    global $DB;
 
-    return get_records_sql("SELECT $fields
-                              FROM {$CFG->prefix}user u
-                                INNER JOIN {$CFG->prefix}groups_members gm ON u.id = gm.userid
-                                INNER JOIN {$CFG->prefix}groupings_groups gg ON gm.groupid = gg.groupid
-                             WHERE  gg.groupingid = $groupingid
-                          ORDER BY $sort");
+    return $DB->get_records_sql("SELECT $fields
+                                   FROM {user} u
+                                     INNER JOIN {groups_members} gm ON u.id = gm.userid
+                                     INNER JOIN {groupings_groups} gg ON gm.groupid = gg.groupid
+                                  WHERE  gg.groupingid = ?
+                               ORDER BY $sort", array($groupingid));
 }
 
 /**
@@ -310,7 +323,7 @@
  * @return integer group mode
  */
 function groups_get_activity_groupmode($cm, $course=null) {
-    global $COURSE;
+    global $COURSE, $DB;
 
     // get course object (reuse COURSE if possible)
     if (isset($course->id) and $course->id == $cm->course) {
@@ -318,7 +331,7 @@
     } else if ($cm->course == $COURSE->id) {
         $course = $COURSE;
     } else {
-        if (!$course = get_record('course', 'id', $cm->course)) {
+        if (!$course = $DB->get_record('course', array('id'=>$cm->course))) {
             error('Incorrect course id in cm');
         }
     }
Index: lib/blocklib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/blocklib.php,v
retrieving revision 1.134
diff -u -r1.134 blocklib.php
--- lib/blocklib.php	15 May 2008 03:07:24 -0000	1.134
+++ lib/blocklib.php	15 May 2008 21:10:56 -0000
@@ -1036,7 +1036,7 @@
 /// This function upgrades the blocks tables, if necessary
 /// It's called from admin/index.php
 
-    global $CFG, $db, $interactive;
+    global $CFG, $interactive, $DB;
 
     require_once ($CFG->dirroot .'/blocks/version.php');  // Get code versions
 
@@ -1050,16 +1050,16 @@
         upgrade_log_start();
         print_heading('blocks');
         if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-        $db->debug=true;
+        $DB->set_debug(true);
         }
     /// Both old .sql files and new install.xml are supported
     /// but we priorize install.xml (XMLDB) if present
         $status = false;
         if (file_exists($CFG->dirroot . '/blocks/db/install.xml')) {
-            $status = install_from_xmldb_file($CFG->dirroot . '/blocks/db/install.xml'); //New method
+            $status = $DB->get_manager()->install_from_xmldb_file($CFG->dirroot . '/blocks/db/install.xml'); //New method
         }
         if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-        $db->debug = false;
+        $DB->set_debug(false);
         }
         if ($status) {
             if (set_config('blocks_version', $blocks_version)) {
@@ -1109,7 +1109,7 @@
         $newupgrade_status = true;
         if ($newupgrade && function_exists($newupgrade_function)) {
             if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-            $db->debug = true;
+                $DB->set_debug(true);
             }
             $newupgrade_status = $newupgrade_function($CFG->blocks_version);
         } else if ($newupgrade) {
@@ -1117,7 +1117,7 @@
                      '/blocks/db/upgrade.php');
         }
         if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-        $db->debug=false;
+            $DB->set_debug(false);
         }
     /// Now analyze upgrade results
         if ($newupgrade_status) {    // No upgrading failed
@@ -1147,7 +1147,7 @@
 //into blocks table or do all the upgrade process if newer
 function upgrade_blocks_plugins($continueto) {
 
-    global $CFG, $db, $interactive;
+    global $CFG, $interactive, $DB;
 
     $blocktitles = array();
     $invalidblocks = array();
@@ -1270,7 +1270,7 @@
                 $newupgrade_status = true;
                 if ($newupgrade && function_exists($newupgrade_function)) {
                     if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-                    $db->debug = true;
+                        $DB->set_debug(true);
                     }
                     $newupgrade_status = $newupgrade_function($currblock->version, $block);
                 } else if ($newupgrade) {
@@ -1278,7 +1278,7 @@
                              $fullblock . '/db/upgrade.php');
                 }
                 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-                $db->debug=false;
+                    $DB->set_debug(false);
                 }
             /// Now analyze upgrade results
                 if ($newupgrade_status) {    // No upgrading failed
@@ -1343,7 +1343,7 @@
             upgrade_log_start();
             print_heading($block->name);
             if (!defined('CLI_UPGRADE')||!CLI_UPGRADE) {
-            $db->debug = true;
+                $DB->set_debug(true);
             }
             @set_time_limit(0);  // To allow slow databases to complete the long SQL
 
@@ -1351,12 +1351,12 @@
         /// but we priorize install.xml (XMLDB) if present
             $status = false;
             if (file_exists($fullblock . '/db/install.xml')) {
-                $status = install_from_xmldb_file($fullblock . '/db/install.xml'); //New method
+                $status = $DB->get_manager()->install_from_xmldb_file($fullblock . '/db/install.xml'); //New method
             } else {
                 $status = true;
             }
             if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-            $db->debug = false;
+                $DB->set_debug(false);
             }
             if ($status) {
                 if ($block->id = insert_record('block', $block)) {
Index: lib/weblib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/weblib.php,v
retrieving revision 1.1072
diff -u -r1.1072 weblib.php
--- lib/weblib.php	15 May 2008 03:07:21 -0000	1.1072
+++ lib/weblib.php	15 May 2008 21:11:16 -0000
@@ -1,4 +1,4 @@
-<?php // $Id: weblib.php,v 1.1072 2008/05/15 03:07:21 dongsheng Exp $
+<?php // $Id: weblib.php,v 1.1071 2008/05/13 12:36:16 sam_marshall Exp $
 
 ///////////////////////////////////////////////////////////////////////////
 //                                                                       //
@@ -33,7 +33,7 @@
  * - datalib.php - functions that access the database.
  * - moodlelib.php - general-purpose Moodle functions.
  * @author Martin Dougiamas
- * @version  $Id: weblib.php,v 1.1072 2008/05/15 03:07:21 dongsheng Exp $
+ * @version  $Id: weblib.php,v 1.1071 2008/05/13 12:36:16 sam_marshall Exp $
  * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  * @package moodlecore
  */
@@ -1375,7 +1375,7 @@
  */
 function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL) {
 
-    global $CFG, $COURSE;
+    global $CFG, $COURSE, $DB;
 
     static $croncache = array();
 
@@ -1420,7 +1420,7 @@
             }
         }
 
-        if ($oldcacheitem = get_record_sql('SELECT * FROM '.$CFG->prefix.'cache_text WHERE md5key = \''.$md5key.'\'', true)) {
+        if ($oldcacheitem = $DB->get_record('cache_text', array('md5key'=>$md5key), '*', true)) {
             if ($oldcacheitem->timemodified >= $time) {
                 if (defined('FULLME') and FULLME == 'cron') {
                     if (count($croncache) > 150) {
@@ -1523,16 +1523,16 @@
 
         $newcacheitem = new object();
         $newcacheitem->md5key = $md5key;
-        $newcacheitem->formattedtext = addslashes($text);
+        $newcacheitem->formattedtext = $text;
         $newcacheitem->timemodified = time();
         if ($oldcacheitem) {                               // See bug 4677 for discussion
             $newcacheitem->id = $oldcacheitem->id;
-            @update_record('cache_text', $newcacheitem);   // Update existing record in the cache table
+            @$DB->update_record('cache_text', $newcacheitem);   // Update existing record in the cache table
                                                            // It's unlikely that the cron cache cleaner could have
                                                            // deleted this entry in the meantime, as it allows
                                                            // some extra time to cover these cases.
         } else {
-            @insert_record('cache_text', $newcacheitem);   // Insert a new record in the cache table
+            @$DB->insert_record('cache_text', $newcacheitem);   // Insert a new record in the cache table
                                                            // Again, it's possible that another user has caused this
                                                            // record to be created already in the time that it took
                                                            // to traverse this function.  That's OK too, as the
@@ -3003,7 +3003,7 @@
  * @return  string    theme name
  */
 function current_category_theme($categoryid=0) {
-    global $COURSE;
+    global $COURSE, $DB;
 
 /// Use the COURSE global if the categoryid not set
     if (empty($categoryid)) {
@@ -3015,7 +3015,7 @@
     }
 
 /// Retrieve the current category
-    if ($category = get_record('course_categories', 'id', $categoryid)) {
+    if ($category = $DB->get_record('course_categories', array('id'=>$categoryid))) {
 
     /// Return the category theme if it exists
         if (!empty($category->theme)) {
@@ -3313,7 +3313,7 @@
  * @return string
  */
 function user_login_string($course=NULL, $user=NULL) {
-    global $USER, $CFG, $SITE;
+    global $USER, $CFG, $SITE, $DB;
 
     if (empty($user) and !empty($USER->id)) {
         $user = $USER;
@@ -3324,7 +3324,7 @@
     }
 
     if (!empty($user->realuser)) {
-        if ($realuser = get_record('user', 'id', $user->realuser)) {
+        if ($realuser = $DB->get_record('user', array('id'=>$user->realuser))) {
             $fullname = fullname($realuser, true);
             $realuserinfo = " [<a $CFG->frametarget
             href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&amp;return=1&amp;sesskey=".sesskey()."\">$fullname</a>] ";
@@ -3347,7 +3347,7 @@
 
         $fullname = fullname($user, true);
         $username = "<a $CFG->frametarget href=\"$CFG->wwwroot/user/view.php?id=$user->id&amp;course=$course->id\">$fullname</a>";
-        if (is_mnet_remote_user($user) and $idprovider = get_record('mnet_host', 'id', $user->mnethostid)) {
+        if (is_mnet_remote_user($user) and $idprovider = $DB->get_record('mnet_host', array('id'=>$user->mnethostid))) {
             $username .= " from <a $CFG->frametarget href=\"{$idprovider->wwwroot}\">{$idprovider->name}</a>";
         }
         if (isset($user->username) && $user->username == 'guest') {
@@ -3355,7 +3355,7 @@
                       " (<a $CFG->frametarget href=\"$wwwroot/login/index.php\">".get_string('login').'</a>)';
         } else if (!empty($user->access['rsw'][$context->path])) {
             $rolename = '';
-            if ($role = get_record('role', 'id', $user->access['rsw'][$context->path])) {
+            if ($role = $DB->get_record('role', array('id'=>$user->access['rsw'][$context->path]))) {
                 $rolename = ': '.format_string($role->name);
             }
             $loggedinas = get_string('loggedinas', 'moodle', $username).$rolename.
@@ -3641,7 +3641,7 @@
  *      navigation strings.
  */
 function build_navigation($extranavlinks, $cm = null) {
-    global $CFG, $COURSE;
+    global $CFG, $COURSE, $DB;
 
     if (is_string($extranavlinks)) {
         if ($extranavlinks == '') {
@@ -3675,7 +3675,7 @@
             debugging('The field $cm->modname should be set if you call build_navigation with '.
                     'a $cm parameter. If you get $cm using get_coursemodule_from_instance or '.
                     'get_coursemodule_from_id, this will be done automatically.', DEBUG_DEVELOPER);
-            if (!$cm->modname = get_field('modules', 'name', 'id', $cm->module)) {
+            if (!$cm->modname = $DB->get_field('modules', 'name', array('id'=>$cm->module))) {
                 print_error('cannotmoduletype');
             }
         }
@@ -3683,7 +3683,7 @@
             debugging('The field $cm->name should be set if you call build_navigation with '.
                     'a $cm parameter. If you get $cm using get_coursemodule_from_instance or '.
                     'get_coursemodule_from_id, this will be done automatically.', DEBUG_DEVELOPER);
-            if (!$cm->name = get_field($cm->modname, 'name', 'id', $cm->instance)) {
+            if (!$cm->name = $DB->get_field($cm->modname, 'name', array('id'=>$cm->instance))) {
                 print_error('cannotmodulename');
             }
         }
@@ -4284,7 +4284,7 @@
  * @todo Finish documenting this function
  */
 function print_user_picture($user, $courseid, $picture=NULL, $size=0, $return=false, $link=true, $target='', $alttext=true) {
-    global $CFG, $HTTPSPAGEREQUIRED;
+    global $CFG, $HTTPSPAGEREQUIRED, $DB;
 
     $needrec = false;
     // only touch the DB if we are missing data...
@@ -4315,7 +4315,7 @@
         }
     }
     if ($needrec) {
-        $user = get_record('user','id',$user, '', '', '', '', 'id,firstname,lastname,imagealt');
+        $user = $DB->get_record('user', array('id'=>$user), 'id,firstname,lastname,imagealt');
     }
 
     if ($link) {
@@ -5208,7 +5208,7 @@
  */
 function navmenu($course, $cm=NULL, $targetwindow='self') {
 
-    global $CFG, $THEME, $USER;
+    global $CFG, $THEME, $USER, $DB;
 
     if (empty($THEME->navmenuwidth)) {
         $width = 50;
@@ -5242,7 +5242,7 @@
     $menu = array();
     $menustyle = array();
 
-    $sections = get_records('course_sections','course',$course->id,'section','section,visible,summary');
+    $sections = $DB->get_records('course_sections', array('course'=>$course->id), 'section', 'section,visible,summary');
 
     if (!empty($THEME->makenavmenulist)) {   /// A hack to produce an XHTML navmenu list for use in themes
         $THEME->navmenulist = navmenulist($course, $sections, $modinfo, $strsection, $strjumpto, $width, $cm);
@@ -6075,7 +6075,7 @@
  * @param bool $return whether to return an output string or echo now
  */
 function notify($message, $style='notifyproblem', $align='center', $return=false) {
-    global $db;
+    global $DB;
 
     if ($style == 'green') {
         $style = 'notifysuccess';  // backward compatible with old color system
@@ -6084,7 +6084,7 @@
     $message = clean_text($message);
     if(!defined('CLI_UPGRADE')||!CLI_UPGRADE) {
     $output = '<div class="'.$style.'" style="text-align:'. $align .'">'. $message .'</div>'."\n";
-    } else if (CLI_UPGRADE && $db->debug) {
+    } else if (CLI_UPGRADE && $DB->get_debug()) {
         $output = '++'.$message.'++';
         return ;
     }
Index: lib/adminlib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/adminlib.php,v
retrieving revision 1.202
diff -u -r1.202 adminlib.php
--- lib/adminlib.php	1 May 2008 20:27:42 -0000	1.202
+++ lib/adminlib.php	15 May 2008 21:10:55 -0000
@@ -42,14 +42,13 @@
 /**
  * Upgrade plugins
  *
- * @uses $db
  * @uses $CFG
  * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
  * @param string $dir  The directory where the plugins are located (e.g. 'question/questiontypes')
  * @param string $return The url to prompt the user to continue to
  */
 function upgrade_plugins($type, $dir, $return) {
-    global $CFG, $db, $interactive;
+    global $CFG, $interactive, $DB;
 
 /// Let's know if the header has been printed, so the funcion is being called embedded in an outer page
     $embedded = defined('HEADER_PRINTED');
@@ -119,7 +118,7 @@
             upgrade_log_start();
             print_heading($dir.'/'. $plugin->name .' plugin needs upgrading');
             if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-                $db->debug = true;
+                $DB->set_debug(true);
             }
             @set_time_limit(0);  // To allow slow databases to complete the long SQL
 
@@ -128,12 +127,12 @@
             /// but we priorize install.xml (XMLDB) if present
                 $status = false;
                 if (file_exists($fullplug . '/db/install.xml')) {
-                    $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
+                    $status = $DB->get_manager()->install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
                 } else {
                     $status = true;
                 }
                 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-                    $db->debug = false;
+                    $DB->set_debug(false);
                 }
             /// Continue with the instalation, roles and other stuff
                 if ($status) {
@@ -170,7 +169,7 @@
                 $newupgrade_status = true;
                 if ($newupgrade && function_exists($newupgrade_function)) {
                     if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-                        $db->debug = true;
+                        $DB->set_debug(true);
                     }
                     $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
                 } else if ($newupgrade) {
@@ -178,7 +177,7 @@
                              $fullplug . '/db/upgrade.php');
                 }
                 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-                    $db->debug=false;
+                    $DB->set_debug(false);
                 }
             /// Now analyze upgrade results
                 if ($newupgrade_status) {    // No upgrading failed
@@ -223,14 +222,13 @@
 /**
  * Find and check all modules and load them up or upgrade them if necessary
  *
- * @uses $db
  * @uses $CFG
  * @param string $return The url to prompt the user to continue to
  * @todo Finish documenting this function
  */
 function upgrade_activity_modules($return) {
 
-    global $CFG, $db, $interactive;
+    global $CFG, $interactive, $DB;
 
     if (!$mods = get_list_of_plugins('mod') ) {
         print_error('No modules installed!');
@@ -289,7 +287,7 @@
 
         include_once($fullmod.'/lib.php');  // defines upgrading and/or installing functions
 
-        if ($currmodule = get_record('modules', 'name', $module->name)) {
+        if ($currmodule = $DB->get_record('modules', array('name'=>$module->name))) {
             if ($currmodule->version == $module->version) {
                 // do nothing
             } else if ($currmodule->version < $module->version) {
@@ -314,7 +312,7 @@
                 $newupgrade_status = true;
                 if ($newupgrade && function_exists($newupgrade_function)) {
                     if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-                    $db->debug = true;
+                        $DB->set_debug(true);
                     }
                     $newupgrade_status = $newupgrade_function($currmodule->version, $module);
                 } else if ($newupgrade) {
@@ -322,13 +320,13 @@
                              $mod . ': ' . $fullmod . '/db/upgrade.php');
                 }
                 if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-                $db->debug=false;
+                    $DB->set_debug(false);
                 }
             /// Now analyze upgrade results
                 if ($newupgrade_status) {    // No upgrading failed
                     // OK so far, now update the modules record
                     $module->id = $currmodule->id;
-                    if (! update_record('modules', $module)) {
+                    if (!$DB->update_record('modules', $module)) {
                         print_error('Could not update '. $module->name .' record in modules table!');
                     }
                     remove_dir($CFG->dataroot . '/cache', true); // flush cache
@@ -366,22 +364,22 @@
             $updated_modules = true;
             // To avoid unnecessary output from the SQL queries in the CLI version
             if (!defined('CLI_UPGRADE')|| !CLI_UPGRADE ) {
-                $db->debug = true;
+                $DB->set_debug(true);
             }
             @set_time_limit(0);  // To allow slow databases to complete the long SQL
 
         /// Both old .sql files and new install.xml are supported
         /// but we priorize install.xml (XMLDB) if present
             if (file_exists($fullmod . '/db/install.xml')) {
-                $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
+                $status = $DB->get_manager()->install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
             }
             if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-                $db->debug = false;
+                $DB->set_debug(false);
             }
 
         /// Continue with the installation, roles and other stuff
             if ($status) {
-                if ($module->id = insert_record('modules', $module)) {
+                if ($module->id = $DB->insert_record('modules', $module)) {
 
                 /// Capabilities
                     if (!update_capabilities('mod/'.$module->name)) {
@@ -461,6 +459,7 @@
  * @return bool true if lock obtained
  */
 function set_cron_lock($name, $until, $ignorecurrent=false) {
+    global $DB;
     if (empty($name)) {
         debugging("Tried to get a cron lock for a null fieldname");
         return false;
@@ -474,7 +473,7 @@
 
     if (!$ignorecurrent) {
         // read value from db - other processes might have changed it
-        $value = get_field('config', 'value', 'name', $name);
+        $value = $DB->get_field('config', 'value', array('name'=>$name));
 
         if ($value and $value > time()) {
             //lock active
@@ -521,7 +520,7 @@
         }
 
         echo '<script>';
-        echo 'document.getElementById("text'.$total.'").innerHTML = "'.addslashes($donetext).' ('.$done.'/'.$total.') '.$projectedtext.'";'."\n";
+        echo 'document.getElementById("text'.$total.'").innerHTML = "'.addslashes_js($donetext).' ('.$done.'/'.$total.') '.$projectedtext.'";'."\n";
         echo 'document.getElementById("slider'.$total.'").style.width = \''.$width.'px\';'."\n";
         echo '</script>';
 
@@ -544,7 +543,7 @@
 }
 
 function create_admin_user($user_input=NULL) {
-    global $CFG, $USER;
+    global $CFG, $USER, $DB;
 
     if (empty($CFG->rolesactive)) {   // No admin user yet.
 
@@ -564,11 +563,11 @@
         if ($user_input) {
             $user = $user_input;
         }
-        if (!$user->id = insert_record('user', $user)) {
+        if (!$user->id = $DB->insert_record('user', $user)) {
             print_error('SERIOUS ERROR: Could not create admin user record !!!');
         }
 
-        if (!$user = get_record('user', 'id', $user->id)) {   // Double check.
+        if (!$user = $DB->get_record('user', array('id'=>$user->id))) {   // Double check.
             print_error('User ID was incorrect (can\'t find it)');
         }
 
@@ -2431,6 +2430,7 @@
     }
 
     function write_setting($data) {
+        global $DB;
         if (!in_array($data, array_keys($this->choices))) {
             return get_string('errorsetting', 'admin');
         }
@@ -2439,7 +2439,7 @@
         $temp                 = $this->name;
         $record->$temp        = $data;
         $record->timemodified = time();
-        return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
+        return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
     }
 }
 
@@ -2538,11 +2538,12 @@
     }
 
     function write_setting($data) {
+        global $DB;
         $record = new object();
         $record->id            = SITEID;
         $record->{$this->name} = ($data == '1' ? 1 : 0);
         $record->timemodified  = time();
-        return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
+        return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
     }
 }
 
@@ -2569,6 +2570,7 @@
     }
 
     function write_setting($data) {
+        global $DB;
         $data = trim($data);
         $validated = $this->validate($data); 
         if ($validated !== true) {
@@ -2577,9 +2579,9 @@
 
         $record = new object();
         $record->id            = SITEID;
-        $record->{$this->name} = addslashes($data);
+        $record->{$this->name} = $data;
         $record->timemodified  = time();
-        return (update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
+        return ($DB->update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
     }
 }
 
@@ -2597,11 +2599,12 @@
     }
 
     function write_setting($data) {
+        global $DB;
         $record = new object();
         $record->id            = SITEID;
-        $record->{$this->name} = addslashes($data);
+        $record->{$this->name} = $data;
         $record->timemodified  = time();
-        return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
+        return($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
     }
 
     function output_html($data, $query='') {
@@ -3166,14 +3169,14 @@
     }
 
     function load_choices() {
-        global $CFG;
+        global $CFG, $DB;
         if (empty($CFG->rolesactive)) {
             return false;
         }
         if (is_array($this->choices)) {
             return true;
         }
-        if ($roles = get_records('role')) {
+        if ($roles = $DB->get_records('role')) {
             $this->choices = array();
             foreach($roles as $role) {
                 $this->choices[$role->id] = format_string($role->name);
@@ -3201,7 +3204,7 @@
 
 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
     function write_setting($data) {
-        global $CFG;
+        global $CFG, $DB;
 
         $oldvalue  = $this->config_read($this->name);
         $return    = parent::write_setting($data);
@@ -3209,7 +3212,7 @@
 
         if ($oldvalue !== $newvalue) {
             // force full regrading
-            set_field('grade_items', 'needsupdate', 1, 'needsupdate', 0);
+            $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0));
         }
 
         return $return;
@@ -3226,10 +3229,11 @@
     }
 
     function load_choices() {
+        global $DB;
         if (is_array($this->choices)) {
             return true;
         }
-        if ($roles = get_records('role')) {
+        if ($roles = $DB->get_records('role')) {
             $this->choices = array();
             foreach($roles as $role) {
                 $this->choices[$role->id] = format_string($role->name);
@@ -3462,12 +3466,13 @@
     }
 
     function search($query) {
+        global $DB;
         if ($result = parent::search($query)) {
             return $result;
         }
 
         $found = false;
-        if ($modules = get_records('modules')) {
+        if ($modules = $DB->get_records('modules')) {
             $textlib = textlib_get_instance();
             foreach ($modules as $module) {
                 if (strpos($module->name, $query) !== false) {
@@ -3502,13 +3507,13 @@
     }
 
     function search($query) {
-        global $CFG;
+        global $CFG, $DB;
         if ($result = parent::search($query)) {
             return $result;
         }
 
         $found = false;
-        if (!empty($CFG->blocks_version) and $blocks = get_records('block')) {
+        if (!empty($CFG->blocks_version) and $blocks = $DB->get_records('block')) {
             $textlib = textlib_get_instance();
             foreach ($blocks as $block) {
                 if (strpos($block->name, $query) !== false) {
@@ -4151,7 +4156,7 @@
  * @return int number of changed settings
  */
 function admin_write_settings($formdata) {
-    global $CFG, $SITE, $COURSE;
+    global $CFG, $SITE, $COURSE, $DB;
 
     $olddbsessions = !empty($CFG->dbsessions);
     $formdata = (array)stripslashes_recursive($formdata);
@@ -4191,7 +4196,7 @@
     }
 
     // now update $SITE - it might have been changed
-    $SITE = get_record('course', 'id', $SITE->id);
+    $SITE = $DB->get_record('course', array('id'=>$SITE->id));
     $COURSE = clone($SITE);
 
     // now reload all settings - some of them might depend on the changed
@@ -4469,36 +4474,36 @@
 
 /**
  * Moved from admin/replace.php so that we can use this in cron
- * @param string $search - string to look for (with magic quotes)
- * @param string $replace - string to replace (with magic quotes)
+ * @param string $search - string to look for
+ * @param string $replace - string to replace
  * @return bool - success or fail
  */
 function db_replace($search, $replace) {
 
-    global $db, $CFG;
+    global $DB, $CFG;
 
     /// Turn off time limits, sometimes upgrades can be slow.
     @set_time_limit(0);
     @ob_implicit_flush(true);
     while(@ob_end_flush());
 
-    if (!$tables = $db->Metatables() ) {    // No tables yet at all.
+    if (!$tables = $DB->get_tables() ) {    // No tables yet at all.
         return false;
     }
     foreach ($tables as $table) {
 
-        if (in_array($table, array($CFG->prefix.'config'))) {      // Don't process these
+        if (in_array($table, array('config'))) {      // Don't process these
             continue;
         }
 
-        if ($columns = $db->MetaColumns($table, false)) {
+        if ($columns = $DB->get_columns($table)) {
+            $DB->set_debug(true);
             foreach ($columns as $column => $data) {
-                if (in_array($data->type, array('text','mediumtext','longtext','varchar'))) {  // Text stuff only
-                    $db->debug = true;
-                    execute_sql("UPDATE $table SET $column = REPLACE($column, '$search', '$replace');");
-                    $db->debug = false;
+                if (in_array($data->meta_type, array('C', 'X'))) {  // Text stuff only
+                    $DB->execute("UPDATE {$CFG->prefix}$table SET $column = REPLACE($column, ?, ?)", array($search, $replace));
                 }
             }
+            $DB->set_debug(false);
         }
     }
 
@@ -4511,6 +4516,7 @@
  * distribution or not.
  */
 function print_plugin_tables() {
+    global $DB;
     $plugins_standard = array();
     $plugins_standard['mod'] = array('assignment',
                                      'chat',
@@ -4571,8 +4577,8 @@
                                         'tidy');
 
     $plugins_installed = array();
-    $installed_mods = get_records_list('modules', '', '', '', 'name');
-    $installed_blocks = get_records_list('block', '', '', '', 'name');
+    $installed_mods = $DB->get_records_list('modules', '', null, '', 'name');
+    $installed_blocks = $DB->get_records_list('block', '', null, '', 'name');
 
     foreach($installed_mods as $mod) {
         $plugins_installed['mod'][] = $mod->name;
Index: lib/filelib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/filelib.php,v
retrieving revision 1.65
diff -u -r1.65 filelib.php
--- lib/filelib.php	6 May 2008 14:59:39 -0000	1.65
+++ lib/filelib.php	15 May 2008 21:11:02 -0000
@@ -733,9 +733,9 @@
 }
 
 function get_records_csv($file, $table) {
-    global $CFG, $db;
+    global $CFG, $DB;
 
-    if (!$metacolumns = $db->MetaColumns($CFG->prefix . $table)) {
+    if (!$metacolumns = $DB->get_columns($table)) {
         return false;
     }
 
@@ -773,14 +773,14 @@
 }
 
 function put_records_csv($file, $records, $table = NULL) {
-    global $CFG, $db;
+    global $CFG, $DB;
 
     if (empty($records)) {
         return true;
     }
 
     $metacolumns = NULL;
-    if ($table !== NULL && !$metacolumns = $db->MetaColumns($CFG->prefix . $table)) {
+    if ($table !== NULL && !$metacolumns = $DB->get_columns($table)) {
         return false;
     }
 
Index: lib/setuplib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/setuplib.php,v
retrieving revision 1.27
diff -u -r1.27 setuplib.php
--- lib/setuplib.php	20 Jan 2008 17:59:26 -0000	1.27
+++ lib/setuplib.php	15 May 2008 21:11:10 -0000
@@ -164,148 +164,6 @@
     return $currdir;
 }
 
-/**
- * This function will introspect inside DB to detect it it's a UTF-8 DB or no
- * Used from setup.php to set correctly "set names" when the installation
- * process is performed without the initial and beautiful installer
- */
-function setup_is_unicodedb() {
-
-    global $CFG, $db, $INSTALL;
-
-    $unicodedb = false;
-    
-    // Calculate $CFG->dbfamily
-    $dbfamily = set_dbfamily();
-
-    switch ($dbfamily) {
-        case 'mysql':
-            $rs = $db->Execute("SHOW LOCAL VARIABLES LIKE 'character_set_database'");
-            if ($rs && !$rs->EOF) { // rs_EOF() not available yet
-                $records = $rs->GetAssoc(true);
-                $encoding = $records['character_set_database']['Value'];
-                if (strtoupper($encoding) == 'UTF8') {
-                    $unicodedb = true;
-                }
-            }
-            break;
-        case 'postgres':
-        /// Get PostgreSQL server_encoding value
-            $rs = $db->Execute("SHOW server_encoding");
-            if ($rs && !$rs->EOF) { // rs_EOF() not available yet
-                $encoding = $rs->fields['server_encoding'];
-                if (strtoupper($encoding) == 'UNICODE' || strtoupper($encoding) == 'UTF8') {
-                    $unicodedb = true;
-                }
-            }
-            break;
-        case 'mssql':
-        /// MSSQL only runs under UTF8 + the proper ODBTP driver (both for Unix and Win32)
-            $unicodedb = true;
-            break;
-        case 'oracle':
-        /// Get Oracle DB character set value
-            $rs = $db->Execute("SELECT parameter, value FROM nls_database_parameters where parameter = 'NLS_CHARACTERSET'");
-            if ($rs && !$rs->EOF) { // rs_EOF() not available yet
-                $encoding = $rs->fields['value'];
-                if (strtoupper($encoding) == 'AL32UTF8') {
-                    $unicodedb = true;
-                }
-            }
-            break;
-    }
-    return $unicodedb;
-}
-
-/**
- * This internal function sets and returns the proper value for $CFG->dbfamily based on $CFG->dbtype
- * It's called by preconfigure_dbconnection() and at install time. Shouldn't be used
- * in other places. Code should rely on dbfamily to perform conditional execution
- * instead of using dbtype directly. This allows quicker adoption of different
- * drivers going against the same DB backend.
- *
- * This function must contain the init code needed for each dbtype supported.
- *
- * return string dbfamily value (mysql, postgres, oracle, mssql)
- */
-function set_dbfamily() {
-
-    global $CFG, $INSTALL;
-
-    // Since this function is also used during installation process, i.e. during install.php before $CFG->dbtype is set.
-    // we need to get dbtype from the right variable 
-    if (!empty($INSTALL['dbtype'])) {
-        $dbtype = $INSTALL['dbtype'];
-    } else {
-        $dbtype = $CFG->dbtype;
-    }
-
-    switch ($dbtype) {
-        case 'mysql':
-        case 'mysqli':
-            $CFG->dbfamily='mysql';
-            break;
-        case 'postgres7':
-            $CFG->dbfamily='postgres';
-            break;
-        case 'mssql':
-        case 'mssql_n':
-        case 'odbc_mssql':
-            $CFG->dbfamily='mssql';
-            break;
-        case 'oci8po':
-            $CFG->dbfamily='oracle';
-            break;
-    }
-
-    return $CFG->dbfamily;
-}
-
-/**
- * This internal function, called from setup.php BEFORE stabilishing the DB
- * connection, defines the $CFG->dbfamily global -by calling set_dbfamily()-
- * and predefines some constants needed by ADOdb to switch some default
- * behaviours.
- *
- * This function must contain all the pre-connection code needed for each
- * dbtype supported.
- */
-function preconfigure_dbconnection() {
-
-    if (defined('ADODB_ASSOC_CASE')) { 
-        return; // when in cli mode, it's possible for this to be called twice (eg cli installer)
-    }
-    global $CFG;
-
-/// Define dbfamily
-    set_dbfamily();
-
-/// Based on $CFG->dbfamily, set some ADOdb settings
-    switch ($CFG->dbfamily) {
-        /// list here family types where we know
-        /// the fieldnames will come in lowercase
-        /// so we can avoid expensive tolower()
-        case 'postgres':
-        case 'mysql':
-        case 'mssql':
-            define ('ADODB_ASSOC_CASE', 2);
-            break;
-        case 'oracle':
-            define ('ADODB_ASSOC_CASE', 0); /// Use lowercase fieldnames for ADODB_FETCH_ASSOC
-                                            /// (only meaningful for oci8po, it's the default
-                                            /// for other DB drivers so this won't affect them)
-            /// Row prefetching uses a bit of memory but saves a ton
-            /// of network latency. With current AdoDB and PHP, only
-            /// Oracle uses this setting.
-            define ('ADODB_PREFETCH_ROWS', 1000);
-            break;
-        default:
-            /// if we have to lowercase it, set to 0
-            /// - note that the lowercasing is very expensive
-            define ('ADODB_ASSOC_CASE', 0); //Use lowercase fieldnames for ADODB_FETCH_ASSOC
-    }
-}
-
 function init_memcached() {
     global $CFG, $MCACHE;
 
Index: lib/ddllib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/ddllib.php,v
retrieving revision 1.63
diff -u -r1.63 ddllib.php
--- lib/ddllib.php	26 Feb 2008 10:34:52 -0000	1.63
+++ lib/ddllib.php	15 May 2008 21:11:00 -0000
@@ -39,646 +39,20 @@
 // For further documentation, visit http://docs.moodle.org/en/DDL_functions
 
 /// Add required XMLDB constants
-    require_once($CFG->libdir . '/xmldb/classes/XMLDBConstants.php');
-
-/// Add main XMLDB Generator
-    require_once($CFG->libdir . '/xmldb/classes/generators/XMLDBGenerator.class.php');
+require_once($CFG->libdir.'/xmldb/XMLDBConstants.php');
 
 /// Add required XMLDB DB classes
-    require_once($CFG->libdir . '/xmldb/classes/XMLDBObject.class.php');
-    require_once($CFG->libdir . '/xmldb/classes/XMLDBFile.class.php');
-    require_once($CFG->libdir . '/xmldb/classes/XMLDBStructure.class.php');
-    require_once($CFG->libdir . '/xmldb/classes/XMLDBTable.class.php');
-    require_once($CFG->libdir . '/xmldb/classes/XMLDBField.class.php');
-    require_once($CFG->libdir . '/xmldb/classes/XMLDBKey.class.php');
-    require_once($CFG->libdir . '/xmldb/classes/XMLDBIndex.class.php');
-    require_once($CFG->libdir . '/xmldb/classes/XMLDBStatement.class.php');
-
-/// Based on $CFG->dbtype, add the proper generator class
-    if (!file_exists($CFG->libdir . '/xmldb/classes/generators/' . $CFG->dbtype . '/' . $CFG->dbtype . '.class.php')) {
-        error ('DB Type: ' . $CFG->dbtype . ' not supported by XMLDDB');
-    }
-    require_once($CFG->libdir . '/xmldb/classes/generators/' . $CFG->dbtype . '/' . $CFG->dbtype . '.class.php');
-
+require_once($CFG->libdir.'/xmldb/XMLDBObject.class.php');
+require_once($CFG->libdir.'/xmldb/XMLDBFile.class.php');
+require_once($CFG->libdir.'/xmldb/XMLDBStructure.class.php');
+require_once($CFG->libdir.'/xmldb/XMLDBTable.class.php');
+require_once($CFG->libdir.'/xmldb/XMLDBField.class.php');
+require_once($CFG->libdir.'/xmldb/XMLDBKey.class.php');
+require_once($CFG->libdir.'/xmldb/XMLDBIndex.class.php');
+require_once($CFG->libdir.'/xmldb/XMLDBStatement.class.php');
 
 /// Add other libraries
-    require_once($CFG->libdir . '/xmlize.php');
-/**
- * Add a new field to a table, or modify an existing one (if oldfield is defined).
- *
- * WARNING: This function is deprecated and will be removed in future versions.
- * Please use XMLDB (see http://docs.moodle.org/en/Development:DDL_functions ).
- *
- * Warning: Please be careful on primary keys, as this function will eat auto_increments
- *
- * @uses $CFG
- * @uses $db
- * @param string $table the name of the table to modify. (Without the prefix.)
- * @param string $oldfield If changing an existing column, the name of that column.
- * @param string $field The name of the column at the end of the operation.
- * @param string $type The type of the column at the end of the operation. TEXT, VARCHAR, CHAR, INTEGER, REAL, or TINYINT
- * @param string $size The size of that column type. As in VARCHAR($size), or INTEGER($size).
- * @param string $signed For numeric column types, whether that column is 'signed' or 'unsigned'.
- * @param string $default The new default value for the column.
- * @param string $null 'not null', or '' to allow nulls.
- * @param string $after Which column to insert this one after. Not supported on Postgres.
- *
- * @return boolean Wheter the operation succeeded.
- */
-function table_column($table, $oldfield, $field, $type='integer', $size='10',
-                      $signed='unsigned', $default='0', $null='not null', $after='') {
-    global $CFG, $db, $empty_rs_cache;
-
-    if (!empty($empty_rs_cache[$table])) {  // Clear the recordset cache because it's out of date
-        unset($empty_rs_cache[$table]);
-    }
-
-    switch (strtolower($CFG->dbtype)) {
-
-        case 'mysql':
-        case 'mysqlt':
-
-            switch (strtolower($type)) {
-                case 'text':
-                    $type = 'TEXT';
-                    $signed = '';
-                    break;
-                case 'integer':
-                    $type = 'INTEGER('. $size .')';
-                    break;
-                case 'varchar':
-                    $type = 'VARCHAR('. $size .')';
-                    $signed = '';
-                    break;
-                case 'char':
-                    $type = 'CHAR('. $size .')';
-                    $signed = '';
-                    break;
-            }
-
-            if (!empty($oldfield)) {
-                $operation = 'CHANGE '. $oldfield .' '. $field;
-            } else {
-                $operation = 'ADD '. $field;
-            }
-
-            $default = 'DEFAULT \''. $default .'\'';
-
-            if (!empty($after)) {
-                $after = 'AFTER `'. $after .'`';
-            }
-
-            return execute_sql('ALTER TABLE '. $CFG->prefix . $table .' '. $operation .' '. $type .' '. $signed .' '. $default .' '. $null .' '. $after);
-
-        case 'postgres7':        // From Petri Asikainen
-            //Check db-version
-            $dbinfo = $db->ServerInfo();
-            $dbver = substr($dbinfo['version'],0,3);
-
-            //to prevent conflicts with reserved words
-            $realfield = '"'. $field .'"';
-            $field = '"'. $field .'_alter_column_tmp"';
-            $oldfield = '"'. $oldfield .'"';
-
-            switch (strtolower($type)) {
-                case 'tinyint':
-                case 'integer':
-                    if ($size <= 4) {
-                        $type = 'INT2';
-                    }
-                    if ($size <= 10) {
-                        $type = 'INT';
-                    }
-                    if  ($size > 10) {
-                        $type = 'INT8';
-                    }
-                    break;
-                case 'varchar':
-                    $type = 'VARCHAR('. $size .')';
-                    break;
-                case 'char':
-                    $type = 'CHAR('. $size .')';
-                    $signed = '';
-                    break;
-            }
-
-            $default = '\''. $default .'\'';
-
-            //After is not implemented in postgesql
-            //if (!empty($after)) {
-            //    $after = "AFTER '$after'";
-            //}
-
-            //Use transactions
-            execute_sql('BEGIN');
-
-            //Always use temporary column
-            execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ADD COLUMN '. $field .' '. $type);
-            //Add default values
-            execute_sql('UPDATE '. $CFG->prefix . $table .' SET '. $field .'='. $default);
-
-
-            if ($dbver >= '7.3') {
-                // modifying 'not null' is posible before 7.3
-                //update default values to table
-                if (strtoupper($null) == 'NOT NULL') {
-                    execute_sql('UPDATE '. $CFG->prefix . $table .' SET '. $field .'='. $default .' WHERE '. $field .' IS NULL');
-                    execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' SET '. $null);
-                } else {
-                    execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' DROP NOT NULL');
-                }
-            }
-
-            execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' SET DEFAULT '. $default);
-
-            if ( $oldfield != '""' ) {
-
-                // We are changing the type of a column. This may require doing some casts...
-                $casting = '';
-                $oldtype = column_type($table, $oldfield);
-                $newtype = column_type($table, $field);
-
-                // Do we need a cast?
-                if($newtype == 'N' && $oldtype == 'C') {
-                    $casting = 'CAST(CAST('.$oldfield.' AS TEXT) AS REAL)';
-                }
-                else if($newtype == 'I' && $oldtype == 'C') {
-                    $casting = 'CAST(CAST('.$oldfield.' AS TEXT) AS INTEGER)';
-                }
-                else {
-                    $casting = $oldfield;
-                }
-
-                // Run the update query, casting as necessary
-                execute_sql('UPDATE '. $CFG->prefix . $table .' SET '. $field .' = '. $casting);
-                execute_sql('ALTER TABLE  '. $CFG->prefix . $table .' DROP COLUMN '. $oldfield);
-            }
-
-            execute_sql('ALTER TABLE '. $CFG->prefix . $table .' RENAME COLUMN '. $field .' TO '. $realfield);
-
-            return execute_sql('COMMIT');
-
-        default:
-            switch (strtolower($type)) {
-                case 'integer':
-                    $type = 'INTEGER';
-                    break;
-                case 'varchar':
-                    $type = 'VARCHAR';
-                    break;
-            }
-
-            $default = 'DEFAULT \''. $default .'\'';
-
-            if (!empty($after)) {
-                $after = 'AFTER '. $after;
-            }
-
-            if (!empty($oldfield)) {
-                execute_sql('ALTER TABLE '. $CFG->prefix . $table .' RENAME COLUMN '. $oldfield .' '. $field);
-            } else {
-                execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ADD COLUMN '. $field .' '. $type);
-            }
-
-            execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' SET '. $null);
-            return execute_sql('ALTER TABLE '. $CFG->prefix . $table .' ALTER COLUMN '. $field .' SET '. $default);
-    }
-}
-
-/**
- * Given one XMLDBTable, check if it exists in DB (true/false)
- *
- * @param XMLDBTable table to be searched for
- * @return boolean true/false
- */
-function table_exists($table) {
-
-    global $CFG, $db;
-
-    $exists = true;
-
-/// Do this function silenty (to avoid output in install/upgrade process)
-    $olddbdebug = $db->debug;
-    $db->debug = false;
-
-/// Load the needed generator
-    $classname = 'XMLDB' . $CFG->dbtype;
-    $generator = new $classname();
-    $generator->setPrefix($CFG->prefix);
-/// Calculate the name of the table
-    $tablename = $generator->getTableName($table, false);
-
-/// Search such tablename in DB
-    $metatables = $db->MetaTables();
-    $metatables = array_flip($metatables);
-    $metatables = array_change_key_case($metatables, CASE_LOWER);
-    if (!array_key_exists($tablename,  $metatables)) {
-        $exists = false;
-    }
-
-/// Re-set original debug 
-    $db->debug = $olddbdebug;
-
-    return $exists;
-}
-
-/**
- * Given one XMLDBField, check if it exists in DB (true/false)
- *
- * @uses, $db
- * @param XMLDBTable the table
- * @param XMLDBField the field to be searched for
- * @return boolean true/false
- */
-function field_exists($table, $field) {
-
-    global $CFG, $db;
-
-    $exists = true;
-
-/// Do this function silenty (to avoid output in install/upgrade process)
-    $olddbdebug = $db->debug;
-    $db->debug = false;
-
-/// Check the table exists
-    if (!table_exists($table)) {
-        $db->debug = $olddbdebug; //Re-set original $db->debug
-        return false;
-    }
-
-/// Load the needed generator
-    $classname = 'XMLDB' . $CFG->dbtype;
-    $generator = new $classname();
-    $generator->setPrefix($CFG->prefix);
-/// Calculate the name of the table
-    $tablename = $generator->getTableName($table, false);
-
-/// Get list of fields in table
-    $fields = null;
-    if ($fields = $db->MetaColumns($tablename)) {
-        $fields = array_change_key_case($fields, CASE_LOWER);
-    }
-
-    if (!array_key_exists($field->getName(),  $fields)) {
-        $exists = false;
-    }
-
-/// Re-set original debug
-    $db->debug = $olddbdebug;
-
-    return $exists;
-}
-
-/**
- * Given one XMLDBIndex, check if it exists in DB (true/false)
- *
- * @uses, $db
- * @param XMLDBTable the table
- * @param XMLDBIndex the index to be searched for
- * @return boolean true/false
- */
-function index_exists($table, $index) {
-
-    global $CFG, $db;
-
-    $exists = true;
-
-/// Do this function silenty (to avoid output in install/upgrade process)
-    $olddbdebug = $db->debug;
-    $db->debug = false;
-
-/// Wrap over find_index_name to see if the index exists
-    if (!find_index_name($table, $index)) {
-        $exists = false;
-    }
-
-/// Re-set original debug
-    $db->debug = $olddbdebug;
-
-    return $exists;
-}
-
-/**
- * Given one XMLDBField, check if it has a check constraint in DB
- *
- * @uses, $db
- * @param XMLDBTable the table
- * @param XMLDBField the field to be searched for any existing constraint
- * @return boolean true/false
- */
-function check_constraint_exists($table, $field) {
-
-    global $CFG, $db;
-
-    $exists = true;
-
-/// Do this function silenty (to avoid output in install/upgrade process)
-    $olddbdebug = $db->debug;
-    $db->debug = false;
-
-/// Wrap over find_check_constraint_name to see if the index exists
-    if (!find_check_constraint_name($table, $field)) {
-        $exists = false;
-    }
-
-/// Re-set original debug
-    $db->debug = $olddbdebug;
-
-    return $exists;
-}
-
-/**
- * This function IS NOT IMPLEMENTED. ONCE WE'LL BE USING RELATIONAL
- * INTEGRITY IT WILL BECOME MORE USEFUL. FOR NOW, JUST CALCULATE "OFFICIAL"
- * KEY NAMES WITHOUT ACCESSING TO DB AT ALL.
- * Given one XMLDBKey, the function returns the name of the key in DB (if exists)
- * of false if it doesn't exist
- *
- * @uses, $db
- * @param XMLDBTable the table to be searched
- * @param XMLDBKey the key to be searched
- * @return string key name of false
- */
-function find_key_name($table, $xmldb_key) {
-
-    global $CFG, $db;
-
-/// Extract key columns
-    $keycolumns = $xmldb_key->getFields();
-
-/// Get list of keys in table
-/// first primaries (we aren't going to use this now, because the MetaPrimaryKeys is awful)
-    ///TODO: To implement when we advance in relational integrity
-/// then uniques (note that Moodle, for now, shouldn't have any UNIQUE KEY for now, but unique indexes)
-    ///TODO: To implement when we advance in relational integrity (note that AdoDB hasn't any MetaXXX for this.
-/// then foreign (note that Moodle, for now, shouldn't have any FOREIGN KEY for now, but indexes)
-    ///TODO: To implement when we advance in relational integrity (note that AdoDB has one MetaForeignKeys()
-    ///but it's far from perfect.
-/// TODO: To create the proper functions inside each generator to retrieve all the needed KEY info (name
-///       columns, reftable and refcolumns
-
-/// So all we do is to return the official name of the requested key without any confirmation!)
-    $classname = 'XMLDB' . $CFG->dbtype;
-    $generator = new $classname();
-    $generator->setPrefix($CFG->prefix);
-/// One exception, harcoded primary constraint names
-    if ($generator->primary_key_name && $xmldb_key->getType() == XMLDB_KEY_PRIMARY) {
-        return $generator->primary_key_name;
-    } else {
-    /// Calculate the name suffix
-        switch ($xmldb_key->getType()) {
-            case XMLDB_KEY_PRIMARY:
-                $suffix = 'pk';
-                break;
-            case XMLDB_KEY_UNIQUE:
-                $suffix = 'uk';
-                break;
-            case XMLDB_KEY_FOREIGN_UNIQUE:
-            case XMLDB_KEY_FOREIGN:
-                $suffix = 'fk';
-                break;
-        }
-    /// And simply, return the oficial name
-        return $generator->getNameForObject($table->getName(), implode(', ', $xmldb_key->getFields()), $suffix);
-    }
-}
-
-/**
- * Given one XMLDBIndex, the function returns the name of the index in DB (if exists)
- * of false if it doesn't exist
- *
- * @uses, $db
- * @param XMLDBTable the table to be searched
- * @param XMLDBIndex the index to be searched
- * @return string index name of false
- */
-function find_index_name($table, $index) {
-
-    global $CFG, $db;
-
-/// Do this function silenty (to avoid output in install/upgrade process)
-    $olddbdebug = $db->debug;
-    $db->debug = false;
-
-/// Extract index columns
-    $indcolumns = $index->getFields();
-
-/// Check the table exists
-    if (!table_exists($table)) {
-        $db->debug = $olddbdebug; //Re-set original $db->debug
-        return false;
-    }
-
-/// Load the needed generator
-    $classname = 'XMLDB' . $CFG->dbtype;
-    $generator = new $classname();
-    $generator->setPrefix($CFG->prefix);
-/// Calculate the name of the table
-    $tablename = $generator->getTableName($table, false);
-
-/// Get list of indexes in table
-    $indexes = null;
-    if ($indexes = $db->MetaIndexes($tablename)) {
-        $indexes = array_change_key_case($indexes, CASE_LOWER);
-    }
-
-/// Iterate over them looking for columns coincidence
-    if ($indexes) {
-        foreach ($indexes as $indexname => $index) {
-            $columns = $index['columns'];
-        /// Lower case column names
-            $columns = array_flip($columns);
-            $columns = array_change_key_case($columns, CASE_LOWER);
-            $columns = array_flip($columns);
-        /// Check if index matchs queried index
-            $diferences = array_merge(array_diff($columns, $indcolumns), array_diff($indcolumns, $columns));
-        /// If no diferences, we have find the index
-            if (empty($diferences)) {
-                $db->debug = $olddbdebug; //Re-set original $db->debug
-                return $indexname;
-            }
-        }
-    }
-/// Arriving here, index not found
-    $db->debug = $olddbdebug; //Re-set original $db->debug
-    return false;
-}
-
-/**
- * Given one XMLDBField, the function returns the name of the check constraint in DB (if exists)
- * of false if it doesn't exist. Note that XMLDB limits the number of check constrainst per field
- * to 1 "enum-like" constraint. So, if more than one is returned, only the first one will be
- * retrieved by this funcion.
- *
- * @uses, $db
- * @param XMLDBTable the table to be searched
- * @param XMLDBField the field to be searched
- * @return string check consrtaint name or false
- */
-function find_check_constraint_name($table, $field) {
-
-    global $CFG, $db;
-
-/// Do this function silenty (to avoid output in install/upgrade process)
-    $olddbdebug = $db->debug;
-    $db->debug = false;
-
-/// Check the table exists
-    if (!table_exists($table)) {
-        $db->debug = $olddbdebug; //Re-set original $db->debug
-        return false;
-    }
-
-/// Check the field exists
-    if (!field_exists($table, $field)) {
-        $db->debug = $olddbdebug; //Re-set original $db->debug
-        return false;
-    }
-
-/// Load the needed generator
-    $classname = 'XMLDB' . $CFG->dbtype;
-    $generator = new $classname();
-    $generator->setPrefix($CFG->prefix);
-/// Calculate the name of the table
-    $tablename = $generator->getTableName($table, false);
-
-/// Get list of check_constraints in table/field
-    $checks = null;
-    if ($objchecks = $generator->getCheckConstraintsFromDB($table, $field)) {
-    /// Get only the 1st element. Shouldn't be more than 1 under XMLDB
-        $objcheck = array_shift($objchecks);
-        if ($objcheck) {
-            $checks = strtolower($objcheck->name);
-        }
-    }
-
-/// Arriving here, check not found
-    $db->debug = $olddbdebug; //Re-set original $db->debug
-    return $checks;
-}
-
-/**
- * Given one XMLDBTable, the function returns the name of its sequence in DB (if exists)
- * of false if it doesn't exist
- *
- * @param XMLDBTable the table to be searched
- * @return string sequence name of false
- */
-function find_sequence_name($table) {
-
-    global $CFG, $db;
-
-    $sequencename = false;
-
-/// Do this function silenty (to avoid output in install/upgrade process)
-    $olddbdebug = $db->debug;
-    $db->debug = false;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        $db->debug = $olddbdebug; //Re-set original $db->debug
-        return false;
-    }
-
-/// Check table exists
-    if (!table_exists($table)) {
-        debugging('Table ' . $table->getName() .
-                  ' does not exist. Sequence not found', DEBUG_DEVELOPER);
-        $db->debug = $olddbdebug; //Re-set original $db->debug
-        return false; //Table doesn't exist, nothing to do
-    }
-
-    $sequencename = $table->getSequenceFromDB($CFG->dbtype, $CFG->prefix);
-
-    $db->debug = $olddbdebug; //Re-set original $db->debug
-    return $sequencename;
-}
-
-/**
- * This function will load one entire XMLDB file, generating all the needed
- * SQL statements, specific for each RDBMS ($CFG->dbtype) and, finally, it
- * will execute all those statements against the DB.
- *
- * @uses $CFG, $db
- * @param $file full path to the XML file to be used
- * @return boolean (true on success, false on error)
- */
-function install_from_xmldb_file($file) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-
-    $xmldb_file = new XMLDBFile($file);
-
-    if (!$xmldb_file->fileExists()) {
-        return false;
-    }
-
-    $loaded = $xmldb_file->loadXMLStructure();
-    if (!$loaded || !$xmldb_file->isLoaded()) {
-    /// Show info about the error if we can find it
-        if ($structure =& $xmldb_file->getStructure()) {
-            if ($errors = $structure->getAllErrors()) {
-                notify('Errors found in XMLDB file: '. implode (', ', $errors));
-            }
-        }
-        return false;
-    }
-
-    $structure = $xmldb_file->getStructure();
-
-    if (!$sqlarr = $structure->getCreateStructureSQL($CFG->dbtype, $CFG->prefix, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr);
-}
-
-/**
- * This function will all tables found in XMLDB file from db
- *
- * @uses $CFG, $db
- * @param $file full path to the XML file to be used
- * @param $feedback
- * @return boolean (true on success, false on error)
- */
-function delete_tables_from_xmldb_file($file, $feedback=true ) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-
-    $xmldb_file = new XMLDBFile($file);
-
-    if (!$xmldb_file->fileExists()) {
-        return false;
-    }
-
-    $loaded    = $xmldb_file->loadXMLStructure();
-    $structure =& $xmldb_file->getStructure();
-
-    if (!$loaded || !$xmldb_file->isLoaded()) {
-    /// Show info about the error if we can find it
-        if ($feedback and $structure) {
-            if ($errors = $structure->getAllErrors()) {
-                notify('Errors found in XMLDB file: '. implode (', ', $errors));
-            }
-        }
-        return false;
-    }
-
-    if ($tables = $structure->getTables()) {
-        foreach($tables as $table) {
-            if (table_exists($table)) {
-                drop_table($table, true, $feedback);
-            }
-        }
-    }
-
-    return true;
-}
+require_once($CFG->libdir.'/xmlize.php');
 
 /**
  * Delete all plugin tables
@@ -687,37 +61,28 @@
  * @feedback boolean
  */
 function drop_plugin_tables($name, $file, $feedback=true) {
-    global $CFG, $db;
+    global $CFG, $DB;
 
     // first try normal delete
-    if (delete_tables_from_xmldb_file($file, $feedback)) {
+    if ($DB->get_manager()->delete_tables_from_xmldb_file($file, $feedback)) {
         return true;
     }
 
     // then try to find all tables that start with name and are not in any xml file
     $used_tables = get_used_table_names();
 
-    $tables = $db->MetaTables();
+    $tables = $DB->get_tables();
+
     /// Iterate over, fixing id fields as necessary
     foreach ($tables as $table) {
-        if (strlen($CFG->prefix)) {
-            if (strpos($table, $CFG->prefix) !== 0) {
-                continue;
-            }
-            $table = substr($table, strlen($CFG->prefix));
-        }
-        $table = strtolower($table);
-        if (strpos($table, $name) !== 0) {
-            continue;
-        }
         if (in_array($table, $used_tables)) {
             continue;
         }
 
         // found orphan table --> delete it
-        $table = new XMLDBTable($table);
-        if (table_exists($table)) {
-            drop_table($table, true, $feedback);
+        if ($DB->get_manager()->table_exists($table)) {
+            $xmldb_table = new XMLDBTable($table);
+            $DB->get_manager()->drop_table($xmldb_table, true, $feedback);
         }
     }
 
@@ -829,735 +194,183 @@
     return $dbdirs;
 }
 
-/**
- * This function will create the table passed as argument with all its
- * fields/keys/indexes/sequences, everything based in the XMLDB object
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
-function create_table($table, $continue=true, $feedback=true) {
 
-    global $CFG, $db;
+// DEPRECATED - to be removed soon
 
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
+function table_exists($table) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->table_exists($table);
+}
 
-/// Check table doesn't exist
-    if (table_exists($table)) {
-        debugging('Table ' . $table->getName() .
-                  ' already exists. Create skipped', DEBUG_DEVELOPER);
-        return true; //Table exists, nothing to do
-    }
+function field_exists($table, $field) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->field_exists($table, $field);
+}
 
-    if(!$sqlarr = $table->getCreateTableSQL($CFG->dbtype, $CFG->prefix, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
+function find_index_name($table, $index) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->find_index_name($table, $index);
+}
 
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+function index_exists($table, $index) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->index_exists($table, $index);
 }
 
-/**
- * This function will drop the table passed as argument
- * and all the associated objects (keys, indexes, constaints, sequences, triggers)
- * will be dropped too.
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
-function drop_table($table, $continue=true, $feedback=true) {
+function find_check_constraint_name($table, $field) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->find_check_constraint_name($table, $field);
+}
 
-    global $CFG, $db;
+function check_constraint_exists($table, $field) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->check_constraint_exists($table, $field);
+}
 
-    $status = true;
+function find_key_name($table, $xmldb_key) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->find_key_name($table, $xmldb_key);
+}
 
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
+function find_sequence_name($table) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->find_sequence_name($table);
+}
 
-/// Check table exists
-    if (!table_exists($table)) {
-        debugging('Table ' . $table->getName() .
-                  ' does not exist. Delete skipped', DEBUG_DEVELOPER);
-        return true; //Table don't exist, nothing to do
-    }
+function drop_table($table, $continue=true, $feedback=true) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->drop_table($table, $continue, $feedback);
+}
 
-    if(!$sqlarr = $table->getDropTableSQL($CFG->dbtype, $CFG->prefix, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
+function install_from_xmldb_file($file) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->install_from_xmldb_file($file);
+}
 
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+function create_table($table, $continue=true, $feedback=true) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->create_table($table, $continue, $feedback);
 }
 
-/**
- * This function will create the temporary table passed as argument with all its
- * fields/keys/indexes/sequences, everything based in the XMLDB object
- *
- * TRUNCATE the table immediately after creation. A previous process using
- * the same persistent connection may have created the temp table and failed to
- * drop it. In that case, the table will exist, and create_temp_table() will
- * will succeed.
- *
- * NOTE: The return value is the tablename - some DBs (MSSQL at least) use special
- * names for temp tables.
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return string tablename on success, false on error
- */
 function create_temp_table($table, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-
-
-    $temporary = 'TEMPORARY';
-    switch (strtolower($CFG->dbfamily)) {
-        case 'mssql':
-            // TODO: somehow change the name to have a #
-            $temporary = '';
-            break;
-        case 'oracle':
-            $temporary = 'GLOBAL TEMPORARY';
-            break;
-    }
-
-/// Check table doesn't exist
-    if (table_exists($table)) {
-        debugging('Table ' . $table->getName() .
-                  ' already exists. Create skipped', DEBUG_DEVELOPER);
-        return $table->getName(); //Table exists, nothing to do
-    }
-
-    if(!$sqlarr = $table->getCreateTableSQL($CFG->dbtype, $CFG->prefix, false)) {
-        return $table->getName(); //Empty array = nothing to do = no error
-    }
-
-    if (!empty($temporary)) {
-        $sqlarr = preg_replace('/^CREATE/', "CREATE $temporary", $sqlarr);
-    }
-
-    if (execute_sql_arr($sqlarr, $continue, $feedback)) {
-        return $table->getName();
-    } else {
-        return false;
-    }
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->create_temp_table($table, $continue, $feedback);
 }
 
-/**
- * This function will rename the table passed as argument
- * Before renaming the index, the function will check it exists
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param string new name of the index
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function rename_table($table, $newname, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-
-/// Check table exists
-    if (!table_exists($table)) {
-        debugging('Table ' . $table->getName() .
-                  ' does not exist. Rename skipped', DEBUG_DEVELOPER);
-        return true; //Table doesn't exist, nothing to do
-    }
-
-/// Check new table doesn't exist
-    $check = new XMLDBTable($newname);
-    if (table_exists($check)) {
-        debugging('Table ' . $check->getName() .
-                  ' already exists. Rename skipped', DEBUG_DEVELOPER);
-        return true; //Table exists, nothing to do
-    }
-
-/// Check newname isn't empty
-    if (!$newname) {
-        debugging('New name for table ' . $table->getName() .
-                  ' is empty! Rename skipped', DEBUG_DEVELOPER);
-        return true; //Table doesn't exist, nothing to do
-    }
-
-    if(!$sqlarr = $table->getRenameTableSQL($CFG->dbtype, $CFG->prefix, $newname, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->rename_table($table, $newname, $continue, $feedback);
 }
 
-/**
- * This function will add the field to the table passed as arguments
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBField field object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function add_field($table, $field, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($field)) != 'xmldbfield') {
-        return false;
-    }
-
-/// Load the needed generator
-    $classname = 'XMLDB' . $CFG->dbtype;
-    $generator = new $classname();
-    $generator->setPrefix($CFG->prefix);
-
-/// Check the field doesn't exist
-    if (field_exists($table, $field)) {
-        debugging('Field ' . $table->getName() . '->' . $field->getName() .
-                  ' already exists. Create skipped', DEBUG_DEVELOPER);
-        return true;
-    }
-
-/// If NOT NULL and no default given (we ask the generator about the
-/// *real* default that will be used) check the table is empty
-    if ($field->getNotNull() && $generator->getDefaultValue($field) === NULL && count_records($table->getName())) {
-        debugging('Field ' . $table->getName() . '->' . $field->getName() .
-                  ' cannot be added. Not null fields added to non empty tables require default value. Create skipped', DEBUG_DEVELOPER);
-         return true;
-    }
-
-    if(!$sqlarr = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->add_field($table, $field, $continue, $feedback);
 }
 
-/**
- * This function will drop the field from the table passed as arguments
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBField field object (just the name is mandatory)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function drop_field($table, $field, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($field)) != 'xmldbfield') {
-        return false;
-    }
-
-/// Check the field exists
-    if (!field_exists($table, $field)) {
-        debugging('Field ' . $table->getName() . '->' . $field->getName() .
-                  ' does not exist. Delete skipped', DEBUG_DEVELOPER);
-        return true;
-    }
-
-    if(!$sqlarr = $table->getDropFieldSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->drop_field($table, $field, $continue, $feedback);
 }
 
-/**
- * This function will change the type of the field in the table passed as arguments
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBField field object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function change_field_type($table, $field, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($field)) != 'xmldbfield') {
-        return false;
-    }
-
-    if(!$sqlarr = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->change_field_type($table, $field, $continue, $feedback);
 }
 
-/**
- * This function will change the precision of the field in the table passed as arguments
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBField field object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function change_field_precision($table, $field, $continue=true, $feedback=true) {
-
-/// Just a wrapper over change_field_type. Does exactly the same processing
-    return change_field_type($table, $field, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->change_field_precision($table, $field, $continue, $feedback);
 }
 
-/**
- * This function will change the unsigned/signed of the field in the table passed as arguments
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBField field object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function change_field_unsigned($table, $field, $continue=true, $feedback=true) {
-
-/// Just a wrapper over change_field_type. Does exactly the same processing
-    return change_field_type($table, $field, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->change_field_unsigned($table, $field, $continue, $feedback);
 }
 
-/**
- * This function will change the nullability of the field in the table passed as arguments
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBField field object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function change_field_notnull($table, $field, $continue=true, $feedback=true) {
-
-/// Just a wrapper over change_field_type. Does exactly the same processing
-    return change_field_type($table, $field, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->change_field_notnull($table, $field, $continue, $feedback);
 }
 
-/**
- * This function will change the enum status of the field in the table passed as arguments
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBField field object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function change_field_enum($table, $field, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($field)) != 'xmldbfield') {
-        return false;
-    }
-
-/// If enum is defined, we're going to create it, check it doesn't exist.
-    if ($field->getEnum()) {
-        if (check_constraint_exists($table, $field)) {
-            debugging('Enum for ' . $table->getName() . '->' . $field->getName() .
-                      ' already exists. Create skipped', DEBUG_DEVELOPER);
-            return true; //Enum exists, nothing to do
-        }
-    } else { /// Else, we're going to drop it, check it exists
-        if (!check_constraint_exists($table, $field)) {
-            debugging('Enum for ' . $table->getName() . '->' . $field->getName() .
-                      ' does not exist. Delete skipped', DEBUG_DEVELOPER);
-            return true; //Enum doesn't exist, nothing to do
-        }
-    }
-
-    if(!$sqlarr = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->change_field_enum($table, $field, $continue, $feedback);
 }
-/**
- * This function will change the default of the field in the table passed as arguments
- * One null value in the default field means delete the default
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBField field object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
-function change_field_default($table, $field, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
 
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($field)) != 'xmldbfield') {
-        return false;
-    }
-
-    if(!$sqlarr = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+function change_field_default($table, $field, $continue=true, $feedback=true) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->change_field_default($table, $field, $continue, $feedback);
 }
 
-/**
- * This function will rename the field in the table passed as arguments
- * Before renaming the field, the function will check it exists
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBField index object (full specs are required)
- * @param string new name of the field
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function rename_field($table, $field, $newname, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($field)) != 'xmldbfield') {
-        return false;
-    }
-
-/// Check we have included full field specs
-    if (!$field->getType()) {
-        debugging('Field ' . $table->getName() . '->' . $field->getName() .
-                  ' must contain full specs. Rename skipped', DEBUG_DEVELOPER);
-        return false;
-    }
-
-/// Check field isn't id. Renaming over that field is not allowed
-    if ($field->getName() == 'id') {
-        debugging('Field ' . $table->getName() . '->' . $field->getName() .
-                  ' cannot be renamed. Rename skipped', DEBUG_DEVELOPER);
-        return true; //Field is "id", nothing to do
-    }
-
-/// Check field exists
-    if (!field_exists($table, $field)) {
-        debugging('Field ' . $table->getName() . '->' . $field->getName() .
-                  ' does not exist. Rename skipped', DEBUG_DEVELOPER);
-        return true; //Field doesn't exist, nothing to do
-    }
-
-/// Check newname isn't empty
-    if (!$newname) {
-        debugging('New name for field ' . $table->getName() . '->' . $field->getName() .
-                  ' is empty! Rename skipped', DEBUG_DEVELOPER);
-        return true; //Field doesn't exist, nothing to do
-    }
-
-    if(!$sqlarr = $table->getRenameFieldSQL($CFG->dbtype, $CFG->prefix, $field, $newname, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->rename_field($table, $field, $continue, $feedback);
 }
 
-/**
- * This function will create the key in the table passed as arguments
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBKey index object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function add_key($table, $key, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($key)) != 'xmldbkey') {
-        return false;
-    }
-    if ($key->getType() == XMLDB_KEY_PRIMARY) { // Prevent PRIMARY to be added (only in create table, being serious  :-P)
-        debugging('Primary Keys can be added at table create time only', DEBUG_DEVELOPER);
-        return true;
-    }
-
-    if(!$sqlarr = $table->getAddKeySQL($CFG->dbtype, $CFG->prefix, $key, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->add_key($table, $key, $continue, $feedback);
 }
 
-/**
- * This function will drop the key in the table passed as arguments
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBKey key object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function drop_key($table, $key, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($key)) != 'xmldbkey') {
-        return false;
-    }
-    if ($key->getType() == XMLDB_KEY_PRIMARY) { // Prevent PRIMARY to be dropped (only in drop table, being serious  :-P)
-        debugging('Primary Keys can be deleted at table drop time only', DEBUG_DEVELOPER);
-        return true;
-    }
-
-    if(!$sqlarr = $table->getDropKeySQL($CFG->dbtype, $CFG->prefix, $key, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->drop_key($table, $key, $continue, $feedback);
 }
 
-/**
- * This function will rename the key in the table passed as arguments
- * Experimental. Shouldn't be used at all in normal installation/upgrade!
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBKey key object (full specs are required)
- * @param string new name of the key
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function rename_key($table, $key, $newname, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    debugging('rename_key() is one experimental feature. You must not use it in production!', DEBUG_DEVELOPER);
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($key)) != 'xmldbkey') {
-        return false;
-    }
-
-/// Check newname isn't empty
-    if (!$newname) {
-        debugging('New name for key ' . $table->getName() . '->' . $key->getName() .
-                  ' is empty! Rename skipped', DEBUG_DEVELOPER);
-        return true; //Key doesn't exist, nothing to do
-    }
-
-    if(!$sqlarr = $table->getRenameKeySQL($CFG->dbtype, $CFG->prefix, $key, $newname, false)) {
-        debugging('Some DBs do not support key renaming (MySQL, PostgreSQL, MsSQL). Rename skipped', DEBUG_DEVELOPER);
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->rename_key($table, $key, $newname, $continue, $feedback);
 }
 
-/**
- * This function will create the index in the table passed as arguments
- * Before creating the index, the function will check it doesn't exists
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBIndex index object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function add_index($table, $index, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($index)) != 'xmldbindex') {
-        return false;
-    }
-
-/// Check index doesn't exist
-    if (index_exists($table, $index)) {
-        debugging('Index ' . $table->getName() . '->' . $index->getName() .
-                  ' already exists. Create skipped', DEBUG_DEVELOPER);
-        return true; //Index exists, nothing to do
-    }
-
-    if(!$sqlarr = $table->getAddIndexSQL($CFG->dbtype, $CFG->prefix, $index, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->add_index($table, $index, $continue, $feedback);
 }
 
-/**
- * This function will drop the index in the table passed as arguments
- * Before dropping the index, the function will check it exists
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBIndex index object (full specs are required)
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function drop_index($table, $index, $continue=true, $feedback=true) {
-
-    global $CFG, $db;
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($index)) != 'xmldbindex') {
-        return false;
-    }
-
-/// Check index exists
-    if (!index_exists($table, $index)) {
-        debugging('Index ' . $table->getName() . '->' . $index->getName() .
-                  ' does not exist. Delete skipped', DEBUG_DEVELOPER);
-        return true; //Index doesn't exist, nothing to do
-    }
-
-    if(!$sqlarr = $table->getDropIndexSQL($CFG->dbtype, $CFG->prefix, $index, false)) {
-        return true; //Empty array = nothing to do = no error
-    }
-
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->drop_index($table, $index, $continue, $feedback);
 }
 
-/**
- * This function will rename the index in the table passed as arguments
- * Before renaming the index, the function will check it exists
- * Experimental. Shouldn't be used at all!
- *
- * @uses $CFG, $db
- * @param XMLDBTable table object (just the name is mandatory)
- * @param XMLDBIndex index object (full specs are required)
- * @param string new name of the index
- * @param boolean continue to specify if must continue on error (true) or stop (false)
- * @param boolean feedback to specify to show status info (true) or not (false)
- * @return boolean true on success, false on error
- */
 function rename_index($table, $index, $newname, $continue=true, $feedback=true) {
+    global $DB;
+    debugging('Deprecated ddllib function used!');
+    return $DB->get_manager()->rename_index($table, $index, $newname, $continue, $feedback);
+}
 
-    global $CFG, $db;
-
-    debugging('rename_index() is one experimental feature. You must not use it in production!', DEBUG_DEVELOPER);
-
-    $status = true;
-
-    if (strtolower(get_class($table)) != 'xmldbtable') {
-        return false;
-    }
-    if (strtolower(get_class($index)) != 'xmldbindex') {
-        return false;
-    }
-
-/// Check index exists
-    if (!index_exists($table, $index)) {
-        debugging('Index ' . $table->getName() . '->' . $index->getName() .
-                  ' does not exist. Rename skipped', DEBUG_DEVELOPER);
-        return true; //Index doesn't exist, nothing to do
-    }
-
-/// Check newname isn't empty
-    if (!$newname) {
-        debugging('New name for index ' . $table->getName() . '->' . $index->getName() .
-                  ' is empty! Rename skipped', DEBUG_DEVELOPER);
-        return true; //Index doesn't exist, nothing to do
-    }
-
-    if(!$sqlarr = $table->getRenameIndexSQL($CFG->dbtype, $CFG->prefix, $index, $newname, false)) {
-        debugging('Some DBs do not support index renaming (MySQL). Rename skipped', DEBUG_DEVELOPER);
-        return true; //Empty array = nothing to do = no error
-    }
+/// DELETED !!
 
-    return execute_sql_arr($sqlarr, $continue, $feedback);
+function table_column($table, $oldfield, $field, $type='integer', $size='10',
+                      $signed='unsigned', $default='0', $null='not null', $after='') {
+    error('table_column() was removed, please use new ddl functions');
 }
 
-/* trys to change default db encoding to utf8, if empty db
- */
-function change_db_encoding() {
-    global $CFG, $db;  
-    // try forcing utf8 collation, if mysql db and no tables present
-    if (($CFG->dbfamily=='mysql') && !$db->Metatables()) {
-        $SQL = 'ALTER DATABASE '.$CFG->dbname.' CHARACTER SET utf8';
-        execute_sql($SQL, false); // silent, if it fails it fails
-        if (setup_is_unicodedb()) {
-            configure_dbconnection();   
-        }
-    }
-}
 
-?>
+?>
\ No newline at end of file
Index: mod/survey/mod_form.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/survey/mod_form.php,v
retrieving revision 1.5
diff -u -r1.5 mod_form.php
--- mod/survey/mod_form.php	4 Apr 2008 02:54:49 -0000	1.5
+++ mod/survey/mod_form.php	15 May 2008 21:11:30 -0000
@@ -5,7 +5,7 @@
 
     function definition() {
 
-        global $CFG;
+        global $CFG, $DB;
         $mform =& $this->_form;
 
         $strrequired = get_string('required');
@@ -17,7 +17,7 @@
         $mform->setType('name', PARAM_TEXT);
         $mform->addRule('name', null, 'required', null, 'client');
 
-        if (!$options = get_records_menu("survey", "template", 0, "name", "id, name")) {
+        if (!$options = $DB->get_records_menu("survey", array("template"=>0), "name", "id, name")) {
             print_error('No survey templates found!');
         }
 
Index: group/overview.php
===================================================================
RCS file: /cvsroot/moodle/moodle/group/overview.php,v
retrieving revision 1.4
diff -u -r1.4 overview.php
--- group/overview.php	4 Apr 2008 02:54:30 -0000	1.4
+++ group/overview.php	15 May 2008 21:10:46 -0000
@@ -43,7 +43,7 @@
     $members    = array(-1 => array()); //groups not in a grouping
     $groupingid = 0;
 } else {
-    if (!$groupings = get_records('groupings', 'courseid', $courseid, 'name')) {
+    if (!$groupings = $DB->get_records('groupings', array('courseid'=>$courseid), 'name')) {
         $groupings = array();
     }
     $members = array();
@@ -54,32 +54,43 @@
 }
 
 // Get all groups
-if (!$groups = get_records('groups', 'courseid', $courseid, 'name')) {
+if (!$groups = $DB->get_records('groups', array('courseid'=>$courseid), 'name')) {
     $groups = array();
 }
 
+$params = array($courseid);
+if ($groupid) {
+    $groupwhere = "AND g.id = ?";
+    $params[]   = $groupid;
+} else {
+    $groupwhere = "";
+}
+
 if (empty($CFG->enablegroupings)) {
-    $groupwhere    = $groupid ? "AND g.id = $groupid" : "";
     $sql = "SELECT g.id AS groupid, NULL AS groupingid, u.id AS userid, u.firstname, u.lastname, u.idnumber, u.username
-              FROM {$CFG->prefix}groups g
-                   LEFT JOIN {$CFG->prefix}groups_members gm ON g.id = gm.groupid
-                   LEFT JOIN {$CFG->prefix}user u ON gm.userid = u.id
-             WHERE g.courseid = {$course->id} $groupwhere
+              FROM {groups} g
+                   LEFT JOIN {groups_members} gm ON g.id = gm.groupid
+                   LEFT JOIN {user} u ON gm.userid = u.id
+             WHERE g.courseid = ? $groupwhere
           ORDER BY g.name, u.lastname, u.firstname";
 } else {
-    $groupingwhere = $groupingid ? "AND gg.groupingid = $groupingid" : "";
-    $groupwhere    = $groupid ? "AND g.id = $groupid" : "";
+    if ($groupingid) {
+        $groupingwhere = "AND gg.groupingid = ";
+        $params[]      = $groupingid;
+    } else {
+        $groupingwhere = "";
+    }
     $sql = "SELECT g.id AS groupid, gg.groupingid, u.id AS userid, u.firstname, u.lastname, u.idnumber, u.username
-              FROM {$CFG->prefix}groups g
-                   LEFT JOIN {$CFG->prefix}groupings_groups gg ON g.id = gg.groupid
-                   LEFT JOIN {$CFG->prefix}groups_members gm ON g.id = gm.groupid
-                   LEFT JOIN {$CFG->prefix}user u ON gm.userid = u.id
-             WHERE g.courseid = {$course->id} $groupingwhere $groupwhere
+              FROM {groups} g
+                   LEFT JOIN {groupings_groups} gg ON g.id = gg.groupid
+                   LEFT JOIN {groups_members} gm ON g.id = gm.groupid
+                   LEFT JOIN {user} u ON gm.userid = u.id
+             WHERE g.courseid = ? $groupwhere $groupingwhere
           ORDER BY g.name, u.lastname, u.firstname";
 }
 
-if ($rs = get_recordset_sql($sql)) {
-    while ($row = rs_fetch_next_record($rs)) {
+if ($rs = $DB->get_recordset_sql($sql, $params)) {
+    foreach ($rs as $row) {
         $user = new object();
         $user->id        = $row->userid;
         $user->firstname = $row->firstname;
Index: group/index.php
===================================================================
RCS file: /cvsroot/moodle/moodle/group/index.php,v
retrieving revision 1.41
diff -u -r1.41 index.php
--- group/index.php	14 May 2008 06:15:56 -0000	1.41
+++ group/index.php	15 May 2008 21:10:46 -0000
@@ -28,7 +28,7 @@
 // Get the course information so we can print the header and
 // check the course id is valid
 
-if (!$course = get_record('course', 'id',$courseid)) {
+if (!$course = $DB->get_record('course', array('id'=>$courseid))) {
     $success = false;
     print_error('invalidcourse'); //'The course ID is invalid'
 }
@@ -141,7 +141,6 @@
 
 
 echo "<td>\n";
-// NO GROUPINGS YET!
 echo '<p><label for="groups"><span id="groupslabel">'.get_string('groups').':</span><span id="thegrouping">&nbsp;</span></label></p>'."\n";
 
 if (ajaxenabled()) {
@@ -166,7 +165,7 @@
             $select = ' selected="selected"';
             $sel_groupid = $group->id;
         }
-        $usercount = (int)count_records('groups_members', 'groupid', $group->id);
+        $usercount = $DB->count_records('groups_members', array('groupid'=>$group->id));
         $groupname = format_string($group->name).' ('.$usercount.')';
 
         echo "<option value=\"{$group->id}\"$select title=\"$groupname\">$groupname</option>\n";
Index: admin/xmldb/actions/main_view/main_view.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/main_view/main_view.class.php,v
retrieving revision 1.11
diff -u -r1.11 main_view.class.php
--- admin/xmldb/actions/main_view/main_view.class.php	15 May 2008 14:54:49 -0000	1.11
+++ admin/xmldb/actions/main_view/main_view.class.php	15 May 2008 21:10:33 -0000
@@ -1,4 +1,4 @@
-<?php // $Id: main_view.class.php,v 1.11 2008/05/15 14:54:49 thepurpleblob Exp $
+<?php // $Id: main_view.class.php,v 1.10 2007/10/10 05:25:30 nicolasconnault Exp $
 
 ///////////////////////////////////////////////////////////////////////////
 //                                                                       //
@@ -68,7 +68,7 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB, $SESSION;
+        global $CFG, $XMLDB, $SESSION, $DB;
 
     /// Get lastused
         $o = '';
@@ -92,7 +92,7 @@
     /// The check defaults button
         $b .= '&nbsp;<a href="index.php?action=check_defaults">[' . $this->str['checkdefaults'] . ']</a>';
     /// The check bigints button (only for MySQL and PostgreSQL) MDL-11038a
-        if ($CFG->dbfamily == 'mysql' || $CFG->dbfamily == 'postgres') {
+        if ($DB->get_dbfamily() == 'mysql' || $DB->get_dbfamily() == 'postgres') {
             $b .= '&nbsp;<a href="index.php?action=check_bigints">[' . $this->str['checkbigints'] . ']</a>';
         }
         $b .= '</p>';
Index: mod/forum/db/upgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/db/upgrade.php,v
retrieving revision 1.10
diff -u -r1.10 upgrade.php
--- mod/forum/db/upgrade.php	1 May 2008 20:44:48 -0000	1.10
+++ mod/forum/db/upgrade.php	15 May 2008 21:11:24 -0000
@@ -39,9 +39,9 @@
         //MDL-13866 - send forum ratins to gradebook again
         require_once($CFG->dirroot.'/mod/forum/lib.php');
         // too much debug output
-        $db->debug = false;
+        $DB->set_debug(false);
         forum_update_grades();
-        $db->debug = true;
+        $DB->set_debug(true);
     }
 
     if ($result && $oldversion < 2007101512) {
@@ -62,12 +62,12 @@
                  WHERE ra.id IS NULL";
 
         if ($rs = get_recordset_sql($sql)) {
-            $db->debug = false;
+            $DB->set_debug(false);
             while ($remove = rs_fetch_next_record($rs)) {
                 delete_records('forum_subscriptions', 'userid', $remove->userid, 'forum', $remove->forumid);
                 echo '.';
             }
-            $db->debug = true;
+            $DB->set_debug(true);
             rs_close($rs);
         }
     }
Index: admin/xmldb/actions/view_table_php/view_table_php.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/view_table_php/view_table_php.class.php,v
retrieving revision 1.15
diff -u -r1.15 view_table_php.class.php
--- admin/xmldb/actions/view_table_php/view_table_php.class.php	1 Nov 2007 23:24:36 -0000	1.15
+++ admin/xmldb/actions/view_table_php/view_table_php.class.php	15 May 2008 21:10:36 -0000
@@ -650,7 +650,7 @@
 
     /**
      * This function will generate all the PHP code needed to
-     * change the enum values (check constraint) of one field 
+     * change the enum values (check constraint) of one field
      * using XMLDB objects and functions
      *
      * @param XMLDBStructure structure object containing all the info
Index: lib/xmldb/classes/generators/odbc_mssql/odbc_mssql.class.php
===================================================================
RCS file: lib/xmldb/classes/generators/odbc_mssql/odbc_mssql.class.php
diff -N lib/xmldb/classes/generators/odbc_mssql/odbc_mssql.class.php
--- lib/xmldb/classes/generators/odbc_mssql/odbc_mssql.class.php	10 Oct 2007 05:25:17 -0000	1.2
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,43 +0,0 @@
-<?php // $Id: odbc_mssql.class.php,v 1.2 2007/10/10 05:25:17 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class generate SQL code to be used against MSSQL
-/// when running over ODBC. As DB is the same, this inherits
-/// everything from XMLDBmssql
-
-require_once($CFG->libdir . '/xmldb/classes/generators/mssql/mssql.class.php');
-
-class XMLDBodbc_mssql extends XMLDBmssql {
-
-    /**
-     * Creates one new XMLDBmssql
-     */
-    function XMLDBodbc_mssql() {
-        XMLDBmssql::XMLDBmssql();
-    }
-}
-
-?>
Index: admin/roles/manage.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/roles/manage.php,v
retrieving revision 1.57
diff -u -r1.57 manage.php
--- admin/roles/manage.php	10 Apr 2008 06:19:07 -0000	1.57
+++ admin/roles/manage.php	15 May 2008 21:10:30 -0000
@@ -14,6 +14,9 @@
     $confirm     = optional_param('confirm', 0, PARAM_BOOL);
     $cancel      = optional_param('cancel', 0, PARAM_BOOL);
 
+    $name        = stripslashes($name);
+    $description = stripslashes($description);
+
     $sitecontext = get_context_instance(CONTEXT_SYSTEM);
 
     require_capability('moodle/role:manage', $sitecontext);
@@ -65,13 +68,13 @@
 
                 if (empty($name)) {
                     $errors['name'] = get_string('errorbadrolename', 'role');
-                } else if (count_records('role', 'name', $name)) {
+                } else if ($DB->count_records('role', array('name'=>$name))) {
                     $errors['name'] = get_string('errorexistsrolename', 'role');
                 }
 
                 if (empty($shortname)) {
                     $errors['shortname'] = get_string('errorbadroleshortname', 'role');
-                } else if (count_records('role', 'shortname', $shortname)) {
+                } else if ($DB->count_records('role', array('shortname'=>$shortname))) {
                     $errors['shortname'] = get_string('errorexistsroleshortname', 'role');
                 }
 
@@ -142,7 +145,7 @@
 
                 if (empty($name)) {
                     $errors['name'] = get_string('errorbadrolename', 'role');
-                } else if ($rs = get_records('role', 'name', $name)) {
+                } else if ($rs = $DB->get_records('role', array('name'=>$name))) {
                     unset($rs[$roleid]);
                     if (!empty($rs)) {
                         $errors['name'] = get_string('errorexistsrolename', 'role');
@@ -151,7 +154,7 @@
 
                 if (empty($shortname)) {
                     $errors['shortname'] = get_string('errorbadroleshortname', 'role');
-                } else if ($rs = get_records('role', 'shortname', $shortname)) {
+                } else if ($rs = $DB->get_records('role', array('shortname'=>$shortname))) {
                     unset($rs[$roleid]);
                     if (!empty($rs)) {
                         $errors['shortname'] = get_string('errorexistsroleshortname', 'role');
@@ -190,11 +193,13 @@
                     }
 
                     // edit default caps
-                    $SQL = "SELECT * FROM {$CFG->prefix}role_capabilities
-                            WHERE roleid = $roleid AND capability = '$capname'
-                              AND contextid = $sitecontext->id";
+                    $SQL = "SELECT *
+                              FROM {role_capabilities}
+                             WHERE roleid = ? AND capability = ?
+                                   AND contextid = ?";
+                    $params = array($roleid, $capname, $sitecontext->id); 
 
-                    $localoverride = get_record_sql($SQL);
+                    $localoverride = $DB->get_record_sql($SQL, $params);
 
                     if ($localoverride) { // update current overrides
                         if ($value == CAP_INHERIT) { // inherit = delete
@@ -204,7 +209,7 @@
                             $localoverride->permission = $value;
                             $localoverride->timemodified = time();
                             $localoverride->modifierid = $USER->id;
-                            update_record('role_capabilities', $localoverride);
+                            $DB->update_record('role_capabilities', $localoverride);
                         }
                     } else { // insert a record
                         if ($value != CAP_INHERIT) {
@@ -221,7 +226,7 @@
                     $role->shortname = $shortname;
                     $role->description = $description;
 
-                    if (!update_record('role', $role)) {
+                    if (!$DB->update_record('role', $role)) {
                         print_error('cannotupdaterole', 'error');
                     }
 
@@ -331,7 +336,7 @@
             }
 
             // duplicate current role
-            $sourcerole = get_record('role','id',$roleid);
+            $sourcerole = $DB->get_record('role', array('id'=>$roleid));
 
             $fullname = $sourcerole->name;
             $shortname = $sourcerole->shortname;
@@ -351,8 +356,8 @@
                 $currentfullname = $fullname.$suffixfull;
                 // Limit the size of shortname - database column accepts <= 100 chars
                 $currentshortname = substr($shortname, 0, 100 - strlen($suffixshort)).$suffixshort;
-                $coursefull  = get_record("role","name",addslashes($currentfullname));
-                $courseshort = get_record("role","shortname",addslashes($currentshortname));
+                $coursefull  = $DB->get_record("role", array("name"=>$currentfullname));
+                $courseshort = $DB->get_record("role", array("shortname"=>$currentshortname));
                 $counter++;
             } while ($coursefull || $courseshort);
 
@@ -365,7 +370,7 @@
                 mark_context_dirty($sitecontext->path);
 
             }
-            $rolename = get_field('role', 'name', 'id', $newrole);
+            $rolename = $DB->get_field('role', 'name', array('id'=>$newrole));
             add_to_log(SITEID, 'role', 'duplicate', 'admin/roles/manage.php?roleid='.$newrole.'&action=duplicate', $rolename, '', $USER->id);
             redirect('manage.php');
             break;
@@ -430,12 +435,12 @@
                 $role->description = '';
                 $role->legacytype  = '';
             } else {
-                $role = stripslashes_safe($newrole);
+                $role = $newrole;
             }
         } else if ($action == 'edit' and !empty($errors) and !empty($newrole)) {
-                $role = stripslashes_safe($newrole);
+                $role = $newrole;
         } else {
-            if(!$role = get_record('role', 'id', $roleid)) {
+            if(!$role = $DB->get_record('role', array('id'=>$roleid))) {
                 print_error('wrongroleid', 'error');
             }
             $role->legacytype = get_legacy_type($role->id);
Index: lib/xmldb/classes/generators/oci8po/oci8po.class.php
===================================================================
RCS file: lib/xmldb/classes/generators/oci8po/oci8po.class.php
diff -N lib/xmldb/classes/generators/oci8po/oci8po.class.php
--- lib/xmldb/classes/generators/oci8po/oci8po.class.php	26 Apr 2008 22:46:03 -0000	1.39
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,643 +0,0 @@
-<?php // $Id: oci8po.class.php,v 1.39 2008/04/26 22:46:03 stronk7 Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class generate SQL code to be used against Oracle
-/// It extends XMLDBgenerator so everything can be
-/// overriden as needed to generate correct SQL.
-
-class XMLDBoci8po extends XMLDBgenerator {
-
-/// Only set values that are different from the defaults present in XMLDBgenerator
-
-    var $statement_end = "\n/"; // String to be automatically added at the end of each statement
-                                // Using "/" because the standard ";" isn't good for stored procedures (triggers)
-
-    var $number_type = 'NUMBER';    // Proper type for NUMBER(x) in this DB
-
-    var $unsigned_allowed = false;    // To define in the generator must handle unsigned information
-    var $default_for_char = ' ';      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
-                                      // Using this whitespace here because Oracle doesn't distinguish empty and null! :-(
-
-    var $drop_default_clause_required = true; //To specify if the generator must use some DEFAULT clause to drop defaults
-    var $drop_default_clause = 'NULL'; //The DEFAULT clause required to drop defaults
-
-    var $default_after_null = false;  //To decide if the default clause of each field must go after the null clause
-
-    var $sequence_extra_code = true; //Does the generator need to add extra code to generate the sequence fields
-    var $sequence_name = ''; //Particular name for inline sequences in this generator
-
-    var $drop_table_extra_code = true; //Does the generator need to add code after table drop
-
-    var $rename_table_extra_code = true; //Does the generator need to add code after table rename
-
-    var $rename_column_extra_code = true; //Does the generator need to add code after field rename
-
-    var $enum_inline_code = false; //Does the generator need to add inline code in the column definition
-
-    var $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY (COLUMNSPECS)'; //The SQL template to alter columns
-
-    /**
-     * Creates one new XMLDBoci8po
-     */
-    function XMLDBoci8po() {
-        parent::XMLDBgenerator();
-        $this->prefix = '';
-        $this->reserved_words = $this->getReservedWords();
-    }
-
-    /**
-     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
-     */
-    function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
-
-        switch ($xmldb_type) {
-            case XMLDB_TYPE_INTEGER:    // From http://www.postgresql.org/docs/7.4/interactive/datatype.html
-                if (empty($xmldb_length)) {
-                    $xmldb_length = 10;
-                }
-                $dbtype = 'NUMBER(' .  $xmldb_length . ')';
-                break;
-            case XMLDB_TYPE_NUMBER:
-                $dbtype = $this->number_type;
-            /// 38 is the max allowed
-                if ($xmldb_length > 38) {
-                    $xmldb_length = 38;
-                }
-                if (!empty($xmldb_length)) {
-                    $dbtype .= '(' . $xmldb_length;
-                    if (!empty($xmldb_decimals)) {
-                        $dbtype .= ',' . $xmldb_decimals;
-                    }
-                    $dbtype .= ')';
-                }
-                break;
-            case XMLDB_TYPE_FLOAT:
-                $dbtype = 'NUMBER';
-                break;
-            case XMLDB_TYPE_CHAR:
-                $dbtype = 'VARCHAR2';
-                if (empty($xmldb_length)) {
-                    $xmldb_length='255';
-                }
-                $dbtype .= '(' . $xmldb_length . ')';
-                break;
-            case XMLDB_TYPE_TEXT:
-                $dbtype = 'CLOB';
-                break;
-            case XMLDB_TYPE_BINARY:
-                $dbtype = 'BLOB';
-                break;
-            case XMLDB_TYPE_DATETIME:
-                $dbtype = 'DATE';
-                break;
-        }
-        return $dbtype;
-    }
-
-    /**
-     * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
-     */
-    function getEnumExtraSQL ($xmldb_table, $xmldb_field) {
-
-        $sql = 'CONSTRAINT ' . $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'ck');
-        $sql.= ' CHECK (' . $this->getEncQuoted($xmldb_field->getName()) . ' IN (' . implode(', ', $xmldb_field->getEnumValues()) . '))';
-
-        return $sql;
-    }
-
-    /**
-     * Returns the code needed to create one sequence for the xmldb_table and xmldb_field passes
-     */
-    function getCreateSequenceSQL ($xmldb_table, $xmldb_field) {
-
-        $results = array();
-
-        $sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
-
-        $sequence = "CREATE SEQUENCE " . $sequence_name;
-        $sequence.= "\n    START WITH 1";
-        $sequence.= "\n    INCREMENT BY 1";
-        $sequence.= "\n    NOMAXVALUE";
-
-        $results[] = $sequence;
-
-        $results = array_merge($results, $this->getCreateTriggerSQL ($xmldb_table, $xmldb_field));
-
-        return $results;
-    }
-
-    /**
-     * Returns the code needed to create one trigger for the xmldb_table and xmldb_field passed
-     */
-    function getCreateTriggerSQL ($xmldb_table, $xmldb_field) {
-
-        $trigger_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'trg');
-        $sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
-
-        $trigger = "CREATE TRIGGER " . $trigger_name;
-        $trigger.= "\n    BEFORE INSERT";
-        $trigger.= "\nON " . $this->getTableName($xmldb_table);
-        $trigger.= "\n    FOR EACH ROW";
-        $trigger.= "\nBEGIN";
-        $trigger.= "\n    IF :new." . $this->getEncQuoted($xmldb_field->getName()) . ' IS NULL THEN';
-        $trigger.= "\n        SELECT " . $sequence_name . '.nextval INTO :new.' . $this->getEncQuoted($xmldb_field->getName()) . " FROM dual;";
-        $trigger.= "\n    END IF;";
-        $trigger.= "\nEND;";
-
-        return array($trigger);
-    }
-
-    /**
-     * Returns the code needed to drop one sequence for the xmldb_table and xmldb_field passed
-     * Can, optionally, specify if the underlying trigger will be also dropped
-     */
-    function getDropSequenceSQL ($xmldb_table, $xmldb_field, $include_trigger=false) {
-
-        $sequence_name = $this->getSequenceFromDB($xmldb_table);
-
-        $sequence = "DROP SEQUENCE " . $sequence_name;
-
-        $trigger_name = $this->getTriggerFromDB($xmldb_table);
-
-        $trigger = "DROP TRIGGER " . $trigger_name;
-
-        if ($include_trigger) {
-            $result =  array($sequence, $trigger);
-        } else {
-            $result = array($sequence);
-        }
-        return $result;
-    }
-
-    /**
-     * Returns the code (in array) needed to add one comment to the table
-     */
-    function getCommentSQL ($xmldb_table) {
-
-        $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
-        $comment.= " IS '" . addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
-
-        return array($comment);
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on field rename
-     */
-    function getRenameFieldExtraSQL ($xmldb_table, $xmldb_field, $newname) {
-
-        $results = array();
-
-    /// If the field is enum, drop and re-create the check constraint
-        if ($xmldb_field->getEnum()) {
-        /// Drop the current enum
-            $results = array_merge($results, $this->getDropEnumSQL($xmldb_table, $xmldb_field));
-        /// Change field name (over a clone to avoid some potential problems later)
-            $new_xmldb_field = clone($xmldb_field);
-            $new_xmldb_field->setName($newname);
-        /// Recreate the enum
-            $results = array_merge($results, $this->getCreateEnumSQL($xmldb_table, $new_xmldb_field));
-        }
-
-        return $results;
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on table drop
-     */
-    function getDropTableExtraSQL ($xmldb_table) {
-        $xmldb_field = new XMLDBField('id'); // Fields having sequences should be exclusively, id.
-        return $this->getDropSequenceSQL($xmldb_table, $xmldb_field, false);
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on table rename
-     */
-    function getRenameTableExtraSQL ($xmldb_table, $newname) {
-
-        $results = array();
-
-        $xmldb_field = new XMLDBField('id'); // Fields having sequences should be exclusively, id.
-
-        $oldseqname = $this->getSequenceFromDB($xmldb_table);
-        $newseqname = $this->getNameForObject($newname, $xmldb_field->getName(), 'seq');
-
-    /// Rename de sequence
-        $results[] = 'RENAME ' . $oldseqname . ' TO ' . $newseqname;
-
-        $oldtriggername = $this->getTriggerFromDB($xmldb_table);
-        $newtriggername = $this->getNameForObject($newname, $xmldb_field->getName(), 'trg');
-
-    /// Drop old trigger
-        $results[] = "DROP TRIGGER " . $oldtriggername;
-
-        $newt = new XMLDBTable($newname); /// Temp table for trigger code generation
-
-    /// Create new trigger
-        $results = array_merge($results, $this->getCreateTriggerSQL($newt, $xmldb_field));
-
-    /// Rename all the check constraints in the table
-        $oldtablename = $this->getTableName($xmldb_table);
-        $newtablename = $this->getTableName($newt);
-
-        $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
-        $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
-
-        if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
-            foreach ($constraints as $constraint) {
-            /// Drop the old constraint
-                $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
-            /// Calculate the new constraint name
-                $newconstraintname = str_replace($oldconstraintprefix, $newconstraintprefix, $constraint->name);
-            /// Add the new constraint
-                $results[] = 'ALTER TABLE ' . $newtablename . ' ADD CONSTRAINT ' . $newconstraintname .
-                             ' CHECK (' . $constraint->description . ')';
-            }
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table
-     * Oracle has some severe limits:
-     *     - clob and blob fields doesn't allow type to be specified
-     *     - error is dropped if the null/not null clause is specified and hasn't changed
-     *     - changes in precision/decimals of numeric fields drop an ORA-1440 error
-     */
-    function getAlterFieldSQL($xmldb_table, $xmldb_field) {
-
-        global $db;
-
-        $results = array(); /// To store all the needed SQL commands
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Take a look to field metadata
-        $meta = array_change_key_case($db->MetaColumns($tablename));
-        $metac = $meta[$fieldname];
-        $oldtype = strtolower($metac->type);
-        $oldmetatype = column_type($xmldb_table->getName(), $fieldname);
-        $oldlength = $metac->max_length;
-    /// To calculate the oldlength if the field is numeric, we need to perform one extra query
-    /// because ADOdb has one bug here. http://phplens.com/lens/lensforum/msgs.php?id=15883
-        if ($oldmetatype == 'N') {
-            $uppertablename = strtoupper($tablename);
-            $upperfieldname = strtoupper($fieldname);
-            if ($col = get_record_sql("SELECT cname, precision
-                                   FROM col
-                                   WHERE tname = '$uppertablename'
-                                     AND cname = '$upperfieldname'")) {
-                $oldlength = $col->precision;
-            }
-        }
-        $olddecimals = empty($metac->scale) ? null : $metac->scale;
-        $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
-        $olddefault = empty($metac->default_value) || strtoupper($metac->default_value) == 'NULL' ? null : $metac->default_value;
-
-        $typechanged = true;  //By default, assume that the column type has changed
-        $precisionchanged = true;  //By default, assume that the column precision has changed
-        $decimalchanged = true;  //By default, assume that the column decimal has changed
-        $defaultchanged = true;  //By default, assume that the column default has changed
-        $notnullchanged = true;  //By default, assume that the column notnull has changed
-
-        $from_temp_fields = false; //By default don't assume we are going to use temporal fields
-
-    /// Detect if we are changing the type of the column
-        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && substr($oldmetatype, 0, 1) == 'I') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_NUMBER  && $oldmetatype == 'N') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_FLOAT   && $oldmetatype == 'F') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_CHAR    && substr($oldmetatype, 0, 1) == 'C') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && substr($oldmetatype, 0, 1) == 'X') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_BINARY  && $oldmetatype == 'B')) {
-            $typechanged = false;
-        } 
-    /// Detect if precision has changed
-        if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
-            ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
-            ($oldlength == -1) ||
-            ($xmldb_field->getLength() == $oldlength)) {
-            $precisionchanged = false;
-        }
-    /// Detect if decimal has changed
-        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) ||
-            ($xmldb_field->getType() == XMLDB_TYPE_CHAR) ||
-            ($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
-            ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
-            (!$xmldb_field->getDecimals()) ||
-            (!$olddecimals) ||
-            ($xmldb_field->getDecimals() == $olddecimals)) {
-            $decimalchanged = false;
-        }
-    /// Detect if we are changing the default
-        if (($xmldb_field->getDefault() === null && $olddefault === null) ||
-            ($xmldb_field->getDefault() === $olddefault) ||             //Check both equality and
-            ("'" . $xmldb_field->getDefault() . "'" === $olddefault)) {  //Equality with quotes because ADOdb returns the default with quotes
-            $defaultchanged = false;
-        }
-
-    /// Detect if we are changing the nullability
-        if (($xmldb_field->getNotnull() === $oldnotnull)) {
-            $notnullchanged = false;
-        }
-
-    /// If type has changed or precision or decimal has changed and we are in one numeric field
-    ///     - create one temp column with the new specs
-    ///     - fill the new column with the values from the old one
-    ///     - drop the old column
-    ///     - rename the temp column to the original name
-        if (($typechanged) || (($oldmetatype == 'N' || $oldmetatype == 'I')  && ($precisionchanged || $decimalchanged))) {
-            $tempcolname = $xmldb_field->getName() . '_alter_column_tmp';
-        /// Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints
-            $this->alter_column_skip_notnull = true;
-            $this->alter_column_skip_default = true;
-            $xmldb_field->setName($tempcolname);
-        /// Create the temporal column
-            $results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field));
-        /// Copy contents from original col to the temporal one
-            $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $fieldname;
-        /// Drop the old column
-            $xmldb_field->setName($fieldname); //Set back the original field name
-            $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
-        /// Rename the temp column to the original one
-            $results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname;
-        /// Mark we have performed one change based in temp fields
-            $from_temp_fields = true;
-        /// Re-enable the notnull and default sections so the general AlterFieldSQL can use it
-            $this->alter_column_skip_notnull = false;
-            $this->alter_column_skip_default = false;
-        /// Dissable the type section because we have done it with the temp field
-            $this->alter_column_skip_type = true;
-        /// If new field is nullable, nullability hasn't changed
-            if (!$xmldb_field->getNotnull()) {
-                $notnullchanged = false;
-            }
-        /// If new field hasn't default, default hasn't changed
-            if ($xmldb_field->getDefault() === null) {
-                $defaultchanged = false;
-            }
-        }
-
-    /// If type and precision and decimals hasn't changed, prevent the type clause
-        if (!$typechanged && !$precisionchanged && !$decimalchanged) {
-            $this->alter_column_skip_type = true;
-        }
-
-    /// If NULL/NOT NULL hasn't changed
-    /// prevent null clause to be specified
-        if (!$notnullchanged) {
-            $this->alter_column_skip_notnull = true; /// Initially, prevent the notnull clause
-        /// But, if we have used the temp field and the new field is not null, then enforce the not null clause
-            if ($from_temp_fields &&  $xmldb_field->getNotnull()) {
-                $this->alter_column_skip_notnull = false;
-            }
-        }
-    /// If default hasn't changed
-    /// prevent default clause to be specified
-        if (!$defaultchanged) {
-            $this->alter_column_skip_default = true; /// Initially, prevent the default clause
-        /// But, if we have used the temp field and the new field has default clause, then enforce the default clause
-            if ($from_temp_fields && $default_clause = $this->getDefaultClause($xmldb_field)) {
-                $this->alter_column_skip_default = false;
-            }
-        }
-
-    /// If arriving here, something is not being skiped (type, notnull, default), calculate the standar AlterFieldSQL
-        if (!$this->alter_column_skip_type || !$this->alter_column_skip_notnull || !$this->alter_column_skip_default) {
-            $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field));
-            return $results;
-        }
-
-    /// Finally return results
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum 
-     * (usually invoked from getModifyEnumSQL()
-     */
-    function getCreateEnumSQL($xmldb_table, $xmldb_field) {
-    /// All we have to do is to create the check constraint
-        return array('ALTER TABLE ' . $this->getTableName($xmldb_table) . 
-                     ' ADD ' . $this->getEnumExtraSQL($xmldb_table, $xmldb_field));
-    }
-                                                       
-    /**     
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum 
-     * (usually invoked from getModifyEnumSQL()
-     */         
-    function getDropEnumSQL($xmldb_table, $xmldb_field) {
-    /// Let's introspect to know the real name of the check constraint
-        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
-            $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
-            $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
-        /// All we have to do is to drop the check constraint
-            return array('ALTER TABLE ' . $this->getTableName($xmldb_table) . 
-                     ' DROP CONSTRAINT ' . $constraint_name);
-        } else { /// Constraint not found. Nothing to do
-            return array();
-        }
-    }   
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */
-    function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
-    /// Just a wrapper over the getAlterFieldSQL() function for Oracle that
-    /// is capable of handling defaults
-        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-    }
-                                                       
-    /**     
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */         
-    function getDropDefaultSQL($xmldb_table, $xmldb_field) {
-    /// Just a wrapper over the getAlterFieldSQL() function for Oracle that
-    /// is capable of handling defaults
-        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-    }   
-
-    /**
-     * Given one XMLDBTable returns one array with all the check constrainsts
-     * in the table (fetched from DB)
-     * Optionally the function allows one xmldb_field to be specified in
-     * order to return only the check constraints belonging to one field.
-     * Each element contains the name of the constraint and its description
-     * If no check constraints are found, returns an empty array
-     */
-    function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
-
-        $results = array();
-
-        $tablename = strtoupper($this->getTableName($xmldb_table));
-
-        if ($constraints = get_records_sql("SELECT lower(c.constraint_name) AS name, c.search_condition AS description
-                                              FROM user_constraints c
-                                             WHERE c.table_name = '{$tablename}'
-                                               AND c.constraint_type = 'C'
-                                               AND c.constraint_name not like 'SYS%'")) {
-            foreach ($constraints as $constraint) {
-                $results[$constraint->name] = $constraint;
-            }
-        }
-
-    /// Filter by the required field if specified
-        if ($xmldb_field) {
-            $filtered_results = array();
-            $filter = $xmldb_field->getName();
-        /// Lets clean a bit each constraint description, looking for the filtered field
-            foreach ($results as $key => $result) {
-            /// description starts by "$filter IN" assume it's a constraint beloging to the field
-                if (preg_match("/^{$filter} IN/i", $result->description)) {
-                    $filtered_results[$key] = $result;
-                }
-            }
-        /// Assign filtered results to the final results array
-            $results =  $filtered_results;
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable returns one string with the sequence of the table
-     * in the table (fetched from DB)
-     * The sequence name for oracle is calculated by looking the corresponding
-     * trigger and retrieving the sequence name from it (because sequences are
-     * independent elements)
-     * If no sequence is found, returns false
-     */
-    function getSequenceFromDB($xmldb_table) {
-
-         $tablename    = strtoupper($this->getTableName($xmldb_table));
-         $prefixupper  = strtoupper($this->prefix);
-         $sequencename = false;
-
-        if ($trigger = get_record_sql("SELECT trigger_name, trigger_body
-                                         FROM user_triggers
-                                        WHERE table_name = '{$tablename}'
-                                          AND trigger_name LIKE '{$prefixupper}%_ID%_TRG'")) {
-        /// If trigger found, regexp it looking for the sequence name
-            preg_match('/.*SELECT (.*)\.nextval/i', $trigger->trigger_body, $matches);
-            if (isset($matches[1])) {
-                $sequencename = $matches[1];
-            }
-        }
-
-        return $sequencename;
-    }
-
-    /**
-     * Given one XMLDBTable returns one string with the trigger
-     * in the table (fetched from DB)
-     * If no trigger is found, returns false
-     */
-    function getTriggerFromDB($xmldb_table) {
-
-        $tablename   = strtoupper($this->getTableName($xmldb_table));
-        $prefixupper = strtoupper($this->prefix);
-        $triggername = false;
-
-        if ($trigger = get_record_sql("SELECT trigger_name, trigger_body
-                                         FROM user_triggers
-                                        WHERE table_name = '{$tablename}'
-                                          AND trigger_name LIKE '{$prefixupper}%_ID%_TRG'")) {
-            $triggername = $trigger->trigger_name;
-        }
-
-        return $triggername;
-    }
-
-    /**
-     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
-     * return if such name is currently in use (true) or no (false)
-     * (invoked from getNameForObject()
-     */
-    function isNameInUse($object_name, $type, $table_name) {
-        switch($type) {
-            case 'ix':
-            case 'uix':
-            case 'seq':
-            case 'trg':
-                if ($check = get_records_sql("SELECT object_name 
-                                              FROM user_objects 
-                                              WHERE lower(object_name) = '" . strtolower($object_name) . "'")) {
-                    return true;
-                }
-                break;
-            case 'pk':
-            case 'uk':
-            case 'fk':
-            case 'ck':
-                if ($check = get_records_sql("SELECT constraint_name 
-                                              FROM user_constraints
-                                              WHERE lower(constraint_name) = '" . strtolower($object_name) . "'")) {
-                    return true;
-                }
-                break;
-        }
-        return false; //No name in use found
-    }
-
-    /**
-     * Returns an array of reserved words (lowercase) for this DB
-     */
-    function getReservedWords() {
-    /// This file contains the reserved words for Oracle databases
-    /// from http://download-uk.oracle.com/docs/cd/B10501_01/server.920/a96540/ap_keywd.htm
-        $reserved_words = array (
-            'access', 'add', 'all', 'alter', 'and', 'any',
-            'as', 'asc', 'audit', 'between', 'by', 'char',
-            'check', 'cluster', 'column', 'comment',
-            'compress', 'connect', 'create', 'current',
-            'date', 'decimal', 'default', 'delete', 'desc',
-            'distinct', 'drop', 'else', 'exclusive', 'exists',
-            'file', 'float', 'for', 'from', 'grant', 'group',
-            'having', 'identified', 'immediate', 'in',
-            'increment', 'index', 'initial', 'insert',
-            'integer', 'intersect', 'into', 'is', 'level',
-            'like', 'lock', 'long', 'maxextents', 'minus',
-            'mlslabel', 'mode', 'modify', 'noaudit',
-            'nocompress', 'not', 'nowait', 'null', 'number',
-            'of', 'offline', 'on', 'online', 'option', 'or',
-            'order', 'pctfree', 'prior', 'privileges',
-            'public', 'raw', 'rename', 'resource', 'revoke',
-            'row', 'rowid', 'rownum', 'rows', 'select',
-            'session', 'set', 'share', 'size', 'smallint',
-            'start', 'successful', 'synonym', 'sysdate',
-            'table', 'then', 'to', 'trigger', 'uid', 'union',
-            'unique', 'update', 'user', 'validate', 'values',
-            'varchar', 'varchar2', 'view', 'whenever',
-            'where', 'with'
-        );
-        return $reserved_words;
-    }
-}
-
-?>
Index: mod/choice/mod_form.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/choice/mod_form.php,v
retrieving revision 1.21
diff -u -r1.21 mod_form.php
--- mod/choice/mod_form.php	23 Nov 2007 22:15:10 -0000	1.21
+++ mod/choice/mod_form.php	15 May 2008 21:11:24 -0000
@@ -97,8 +97,9 @@
     }
 
     function data_preprocessing(&$default_values){
-        if (!empty($this->_instance) && ($options = get_records_menu('choice_options','choiceid', $this->_instance, 'id', 'id,text'))
-               && ($options2 = get_records_menu('choice_options','choiceid', $this->_instance, 'id', 'id,maxanswers')) ) {
+        global $DB;
+        if (!empty($this->_instance) && ($options = $DB->get_records_menu('choice_options',array('choiceid'=>$this->_instance), 'id', 'id,text'))
+               && ($options2 = $DB->get_records_menu('choice_options', array('choiceid'=>$this->_instance), 'id', 'id,maxanswers')) ) {
             $choiceids=array_keys($options);
             $options=array_values($options);
             $options2=array_values($options2);
Index: admin/xmldb/actions/check_indexes/check_indexes.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/check_indexes/check_indexes.class.php,v
retrieving revision 1.6
diff -u -r1.6 check_indexes.class.php
--- admin/xmldb/actions/check_indexes/check_indexes.class.php	10 Oct 2007 05:25:22 -0000	1.6
+++ admin/xmldb/actions/check_indexes/check_indexes.class.php	15 May 2008 21:10:31 -0000
@@ -74,7 +74,9 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB;
+        global $CFG, $XMLDB, $DB;
+
+        $dbman = $DB->get_manager();
 
     /// And we nedd some ddl suff
         require_once ($CFG->libdir . '/ddllib.php');
@@ -123,10 +125,6 @@
                     }
                 /// Load the XML file
                     $xmldb_file = new XMLDBFile($dbdir->path . '/install.xml');
-                /// Load the needed XMLDB generator
-                    $classname = 'XMLDB' . $CFG->dbtype;
-                    $generator = new $classname();
-                    $generator->setPrefix($CFG->prefix);
 
                 /// Only if the file exists
                     if (!$xmldb_file->fileExists()) {
@@ -147,7 +145,7 @@
                     /// Foreach table, process its indexes and keys
                         foreach ($xmldb_tables as $xmldb_table) {
                         /// Skip table if not exists
-                            if (!table_exists($xmldb_table)) {
+                            if (!$dbman->table_exists($xmldb_table)) {
                                 continue;
                             }
                             $o.='            <li>' . $xmldb_table->getName();
@@ -163,7 +161,7 @@
                                     }
                                 /// If we aren't creating the keys or the key is a XMLDB_KEY_FOREIGN (not underlying index generated
                                 /// automatically by the RDBMS) create the underlying (created by us) index (if doesn't exists)
-                                    if (!$generator->getKeySQL($xmldb_table, $xmldb_key) || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
+                                    if (!$dbman->generator->getKeySQL($xmldb_table, $xmldb_key) || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
                                     /// Create the interim index
                                         $xmldb_index = new XMLDBIndex('anyname');
                                         $xmldb_index->setFields($xmldb_key->getFields());
@@ -177,7 +175,7 @@
                                                 break;
                                         }
                                     /// Check if the index exists in DB
-                                        if (index_exists($xmldb_table, $xmldb_index)) {
+                                        if ($dbman->index_exists($xmldb_table, $xmldb_index)) {
                                             $o.='<font color="green">' . $this->str['ok'] . '</font>';
                                         } else {
                                             $o.='<font color="red">' . $this->str['missing'] . '</font>';
@@ -198,7 +196,7 @@
                                 foreach ($xmldb_indexes as $xmldb_index) {
                                     $o.='            <li>' . $this->str['index'] . ': ' . $xmldb_index->readableInfo() . ' ';
                                 /// Check if the index exists in DB
-                                    if (index_exists($xmldb_table, $xmldb_index)) {
+                                    if ($dbman->index_exists($xmldb_table, $xmldb_index)) {
                                         $o.='<font color="green">' . $this->str['ok'] . '</font>';
                                     } else {
                                         $o.='<font color="red">' . $this->str['missing'] . '</font>';
@@ -237,11 +235,12 @@
                 foreach ($missing_indexes as $obj) {
                     $xmldb_table = $obj->table;
                     $xmldb_index = $obj->index;
-                    $sqlarr = $xmldb_table->getAddIndexSQL($CFG->dbtype, $CFG->prefix, $xmldb_index, true);
+                    $sqlarr = $dbman->generator->getAddIndexSQL($xmldb_table, $xmldb_index);
                     $r.= '            <li>' . $this->str['table'] . ': ' . $xmldb_table->getName() . '. ' .
                                               $this->str['index'] . ': ' . $xmldb_index->readableInfo() . '</li>';
+                    $sqlarr = $dbman->generator->getEndedStatements($sqlarr);
                     $s.= '<code>' . str_replace("\n", '<br />', implode('<br />', $sqlarr)) . '</code><br />';
-                    
+
                 }
                 $r.= '        </ul>';
             /// Add the SQL statements (all together)
Index: lib/xmldb/classes/generators/mysqli/mysqli.class.php
===================================================================
RCS file: lib/xmldb/classes/generators/mysqli/mysqli.class.php
diff -N lib/xmldb/classes/generators/mysqli/mysqli.class.php
--- lib/xmldb/classes/generators/mysqli/mysqli.class.php	10 Oct 2007 05:25:28 -0000	1.2
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,43 +0,0 @@
-<?php // $Id: mysqli.class.php,v 1.2 2007/10/10 05:25:28 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class generate SQL code to be used against MySQL
-/// when running over mysqli (improved). As DB is the same, this inherits
-/// everything from XMLDBmysql
-
-require_once($CFG->libdir . '/xmldb/classes/generators/mysql/mysql.class.php');
-
-class XMLDBmysqli extends XMLDBmysql {
-
-    /**
-     * Creates one new XMLDBmysql
-     */
-    function XMLDBmysqli() {
-        XMLDBmysql::XMLDBmysql();
-    }
-}
-
-?>
Index: admin/xmldb/actions/edit_xml_file/edit_xml_file.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/edit_xml_file/edit_xml_file.class.php,v
retrieving revision 1.6
diff -u -r1.6 edit_xml_file.class.php
--- admin/xmldb/actions/edit_xml_file/edit_xml_file.class.php	10 Oct 2007 05:25:26 -0000	1.6
+++ admin/xmldb/actions/edit_xml_file/edit_xml_file.class.php	15 May 2008 21:10:33 -0000
@@ -72,7 +72,7 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB;
+        global $CFG, $XMLDB, $DB;
 
     /// Do the job, setting $result as needed
 
@@ -127,7 +127,7 @@
             /// The new table button
                 $b .= '&nbsp;<a href="index.php?action=new_table&amp;postaction=edit_table&amp;table=changeme&amp;dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '">[' . $this->str['newtable'] . ']</a>';
             /// The new from MySQL button
-                if ($CFG->dbfamily == 'mysql') {
+                if ($DB->get_dbfamily() == 'mysql') {
                     $b .= '&nbsp;<a href="index.php?action=new_table_from_mysql&amp;dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '">[' . $this->str['newtablefrommysql'] . ']</a>';
                 } else {
                     $b .= '&nbsp;[' . $this->str['newtablefrommysql'] . ']';
@@ -146,17 +146,12 @@
                 $o .= $b;
             /// Join all the reserved words into one big array
             /// Calculate list of available SQL generators
-                $plugins = get_list_of_plugins('lib/xmldb/classes/generators');
-                $reserved_words = array();
-                foreach($plugins as $plugin) {
-                    $classname = 'XMLDB' . $plugin;
-                    $generator = new $classname();
-                    $reserved_words = array_merge($reserved_words, $generator->getReservedWords());
-                }
-                sort($reserved_words);
-                $reserved_words = array_unique($reserved_words);
+
+                require("$CFG->libdir/ddl/sql_generator.php");
+                $reserved_words = sql_generator::getAllReservedWords();
+
             /// Add the tables list
-                $tables =& $structure->getTables();
+                $tables = $structure->getTables();
                 if ($tables) {
                     $o .= '<h3 class="main">' . $this->str['tables'] . '</h3>';
                     $o .= '<table id="listtables" border="0" cellpadding="5" cellspacing="1" class="boxaligncenter flexible">';
@@ -190,7 +185,7 @@
                             $b .= '[' . $this->str['delete'] . ']';
                         }
                     /// Detect if the table name is a reserved word
-                         if (in_array($table->getName(), $reserved_words)) {
+                         if (array_key_exists($table->getName(), $reserved_words)) {
                              $b .= '&nbsp;<a href="index.php?action=view_reserved_words"><span class="error">' . $this->str['reserved'] . '</span></a>';
                          }
                         $b .= '</td>';
Index: admin/xmldb/actions/new_statement/new_statement.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/new_statement/new_statement.class.php,v
retrieving revision 1.5
diff -u -r1.5 new_statement.class.php
--- admin/xmldb/actions/new_statement/new_statement.class.php	10 Oct 2007 05:25:23 -0000	1.5
+++ admin/xmldb/actions/new_statement/new_statement.class.php	15 May 2008 21:10:33 -0000
@@ -60,7 +60,7 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB, $db;
+        global $CFG, $XMLDB, $DB;
 
     /// Do the job, setting result as needed
     /// Get the dir containing the file
@@ -86,12 +86,7 @@
         /// No postaction here
             $this->postaction = NULL;
         /// Get list of tables
-            $dbtables = $db->MetaTables('TABLES');
-            $selecttables = array();
-            foreach ($dbtables as $dbtable) {
-                $dbtable = str_replace($CFG->prefix, '', $dbtable);
-                $selecttables[$dbtable] = $dbtable;
-            }
+            $selecttables = $DB->get_tables();
         /// Get list of statement types
             $typeoptions = array (XMLDB_STATEMENT_INSERT => XMLDBStatement::getXMLDBStatementName(XMLDB_STATEMENT_INSERT),
                                   XMLDB_STATEMENT_UPDATE => XMLDBStatement::getXMLDBStatementName(XMLDB_STATEMENT_UPDATE),
Index: course/edit_form.php
===================================================================
RCS file: /cvsroot/moodle/moodle/course/edit_form.php,v
retrieving revision 1.45
diff -u -r1.45 edit_form.php
--- course/edit_form.php	13 May 2008 06:16:51 -0000	1.45
+++ course/edit_form.php	15 May 2008 21:10:42 -0000
@@ -5,7 +5,7 @@
 class course_edit_form extends moodleform {
 
     function definition() {
-        global $USER, $CFG;
+        global $USER, $CFG, $DB;
 
         $mform    =& $this->_form;
 
@@ -350,7 +350,7 @@
             $options['1'] = get_string('yes');
             $mform->addElement('select', 'restrictmodules', get_string('restrictmodules'), $options);
             $mods = array(0=>get_string('allownone'));
-            $mods += get_records_menu('modules', '','','','id, name');
+            $mods += get_records_menu('modules', array() ,'name','id, name');
 
 
             $mform->addElement('select', 'allowedmods', get_string('to'), $mods,
Index: course/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/course/lib.php,v
retrieving revision 1.592
diff -u -r1.592 lib.php
--- course/lib.php	13 May 2008 22:04:06 -0000	1.592
+++ course/lib.php	15 May 2008 21:10:45 -0000
@@ -1535,7 +1535,7 @@
  * @param boolean $clearonly - only clear the modinfo fields, gets rebuild automatically on the fly
  */
 function rebuild_course_cache($courseid=0, $clearonly=false) {
-    global $COURSE;
+    global $COURSE, $DB;
 
     if ($clearonly) {
         $courseselect = empty($courseid) ? "" : "id = $courseid";
@@ -2581,6 +2581,7 @@
  * Print groupmode form element on module setup forms in mod/.../mod.html
  */
 function print_grouping_settings($form, $course=NULL) {
+    global $DB;
 
     if (empty($course)) {
         if (! $course = get_record('course', 'id', $form->course)) {
@@ -2595,13 +2596,12 @@
         $cm = null;
     }
 
-    $groupings = get_records_menu('groupings', 'courseid', $course->id, 'name', 'id, name');
+    $groupings = $DB->get_records_menu('groupings', array('courseid'=>$course->id), 'name', 'id, name');
     if (!empty($groupings)) {
         echo '<tr valign="top">';
         echo '<td align="right"><b>'.get_string('grouping', 'group').':</b></td>';
         echo '<td align="left">';
         
-        $groupings;
         $groupingid = isset($cm->groupingid) ? $cm->groupingid : 0;
         
         choose_from_menu($groupings, 'groupingid', $groupingid, get_string('none'), '', 0, false);
Index: admin/mnet/access_control.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/mnet/access_control.php,v
retrieving revision 1.16
diff -u -r1.16 access_control.php
--- admin/mnet/access_control.php	2 Apr 2008 07:17:11 -0000	1.16
+++ admin/mnet/access_control.php	15 May 2008 21:10:30 -0000
@@ -27,7 +27,7 @@
 $formerror = array();
 
 // grab the mnet hosts and remove the localhost
-$mnethosts = get_records_menu('mnet_host', '', '', 'name', 'id, name');
+$mnethosts = $DB->get_records_menu('mnet_host', array(), 'name', 'id, name');
 if (array_key_exists($CFG->mnet_localhost_id, $mnethosts)) {
     unset($mnethosts[$CFG->mnet_localhost_id]);
 }
Index: calendar/event.php
===================================================================
RCS file: /cvsroot/moodle/moodle/calendar/event.php,v
retrieving revision 1.80
diff -u -r1.80 event.php
--- calendar/event.php	7 May 2008 07:40:50 -0000	1.80
+++ calendar/event.php	15 May 2008 21:10:42 -0000
@@ -158,8 +158,8 @@
                         }
 
                         execute_sql('UPDATE '.$CFG->prefix.'event SET '.
-                            'name = '.$db->qstr($form->name).','.
-                            'description = '.$db->qstr($form->description).','.
+                            'name = '.addslashes($form->name).','.
+                            'description = '.addslashes($form->description).','.
                             'timestart = '.$timestartoffset.','.
                             'timeduration = '.$form->timeduration.','.
                             'timemodified = '.time().' WHERE repeatid = '.$event->repeatid);
Index: mod/wiki/ewiki/plugins/page/orphanedpages.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/wiki/ewiki/plugins/page/orphanedpages.php,v
retrieving revision 1.1
diff -u -r1.1 orphanedpages.php
--- mod/wiki/ewiki/plugins/page/orphanedpages.php	2 Jun 2004 18:17:30 -0000	1.1
+++ mod/wiki/ewiki/plugins/page/orphanedpages.php	15 May 2008 21:11:30 -0000
@@ -19,9 +19,9 @@
    $orphaned = array();
 
    #-- read database
-   $db = ewiki_database("GETALL", array("refs", "flags"));
+   $datab = ewiki_database("GETALL", array("refs", "flags"));
    $n=0;
-   while ($row = $db->get()) {
+   while ($row = $datab->get()) {
 
       $p = $row["id"];
 
Index: admin/xmldb/actions/view_table_sql/view_table_sql.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/view_table_sql/view_table_sql.class.php,v
retrieving revision 1.5
diff -u -r1.5 view_table_sql.class.php
--- admin/xmldb/actions/view_table_sql/view_table_sql.class.php	10 Oct 2007 05:25:27 -0000	1.5
+++ admin/xmldb/actions/view_table_sql/view_table_sql.class.php	15 May 2008 21:10:36 -0000
@@ -58,7 +58,8 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB;
+        global $CFG, $XMLDB, $DB;
+        $dbman = $DB->get_manager();
 
     /// Do the job, setting result as needed
     /// Get the dir containing the file
@@ -79,25 +80,10 @@
 
     /// Get parameters
         $tableparam = required_param('table', PARAM_PATH);
-        if (!$table =& $structure->getTable($tableparam)) {
-            $this->errormsg = 'Wrong table specified: ' . $tableparm;
+        if (!$table = $structure->getTable($tableparam)) {
+            $this->errormsg = 'Wrong table specified: ' . $tableparam;
             return false;
         }
-        $generatorparam = optional_param('generator', null, PARAM_ALPHANUM);
-        if (empty($generatorparam)) {
-            $generatorparam = $CFG->dbtype;
-        }
-
-    /// Calculate list of available SQL generators
-        $plugins = get_list_of_plugins('lib/xmldb/classes/generators');
-        $generators = array();
-        foreach($plugins as $plugin) {
-            $generators[$plugin] = $plugin;
-        }
-    /// Check we have the selected generator
-        if (!in_array($generatorparam, $generators)) {
-            $generatorparam = reset($generators);
-        }
 
         /// The back to edit table button
         $b = ' <p class="centerpara buttons">';
@@ -106,15 +92,11 @@
         $o = $b;
 
         $o.= '    <table id="formelements" class="boxaligncenter" cellpadding="5">';
-        $o.= '      <tr><td align="center">' . $this->str['selectdb'];
-
-    /// Show the popup of generators
-        $url = 'index.php?action=view_table_sql&amp;table=' . $tableparam . '&amp;dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '&amp;generator=';
-        $o.= popup_form($url, $generators, 'selectgenerator', $generatorparam, '', '', '' , true);
-        $o.= '      </td></tr>';
         $o.= '      <tr><td><textarea cols="80" rows="32">';
+
     /// Get an array of statements
-        if ($starr = $table->getCreateTableSQL($generatorparam, $CFG->prefix)) {
+        if ($starr = $DB->get_manager()->generator->getCreateTableSQL($table)) {
+            $starr = $dbman->generator->getEndedStatements($starr);
             $sqltext = '';
             foreach ($starr as $st) {
                 $sqltext .= s($st) . "\n\n";
Index: auth/cas/auth.php
===================================================================
RCS file: /cvsroot/moodle/moodle/auth/cas/auth.php,v
retrieving revision 1.23
diff -u -r1.23 auth.php
--- auth/cas/auth.php	25 Apr 2008 13:22:02 -0000	1.23
+++ auth/cas/auth.php	15 May 2008 21:10:37 -0000
@@ -592,6 +592,10 @@
                                  /// some persistent drivers like ODBTP (mssql) or if this function is invoked
                                  /// from within a PHP application using persistent connections
         // configure a temp table
+
+/// TODO: remove these ugly hacks
+error('fix temporary table code in CAS');
+
         print "Configuring temp table\n";
         switch (strtolower($CFG->dbfamily)) {
             case 'mysql':
Index: admin/xmldb/actions/edit_statement/edit_statement.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/edit_statement/edit_statement.class.php,v
retrieving revision 1.6
diff -u -r1.6 edit_statement.class.php
--- admin/xmldb/actions/edit_statement/edit_statement.class.php	10 Oct 2007 05:25:30 -0000	1.6
+++ admin/xmldb/actions/edit_statement/edit_statement.class.php	15 May 2008 21:10:32 -0000
@@ -103,7 +103,7 @@
 
     /// Add the main form
         $o = '<form id="form" action="index.php" method="post">';
-        $o.= '<div>';        
+        $o.= '<div>';
         $o.= '    <input type="hidden" name ="dir" value="' . str_replace($CFG->dirroot, '', $dirpath) . '" />';
         $o.= '    <input type="hidden" name ="statement" value="' . $statementparam .'" />';
         $o.= '    <input type="hidden" name ="action" value="edit_statement_save" />';
Index: lib/xmldb/classes/generators/mssql/mssql.class.php
===================================================================
RCS file: lib/xmldb/classes/generators/mssql/mssql.class.php
diff -N lib/xmldb/classes/generators/mssql/mssql.class.php
--- lib/xmldb/classes/generators/mssql/mssql.class.php	10 Oct 2007 05:25:18 -0000	1.41
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,568 +0,0 @@
-<?php // $Id: mssql.class.php,v 1.41 2007/10/10 05:25:18 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class generate SQL code to be used against MSSQL
-/// It extends XMLDBgenerator so everything can be
-/// overriden as needed to generate correct SQL.
-
-class XMLDBmssql extends XMLDBgenerator {
-
-/// Only set values that are different from the defaults present in XMLDBgenerator
-
-    var $statement_end = "\ngo"; // String to be automatically added at the end of each statement
-
-    var $number_type = 'DECIMAL';    // Proper type for NUMBER(x) in this DB
-
-    var $unsigned_allowed = false;    // To define in the generator must handle unsigned information
-    var $default_for_char = '';      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
-
-    var $specify_nulls = true;  //To force the generator if NULL clauses must be specified. It shouldn't be necessary
-                                     //but some mssql drivers require them or everything is created as NOT NULL :-(
-
-    var $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
-    var $sequence_name = 'IDENTITY(1,1)'; //Particular name for inline sequences in this generator
-    var $sequence_only = false; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable
-
-    var $enum_inline_code = false; //Does the generator need to add inline code in the column definition
-
-    var $add_table_comments  = false;  // Does the generator need to add code for table comments
-
-    var $concat_character = '+'; //Characters to be used as concatenation operator. If not defined
-                                  //MySQL CONCAT function will be use
-
-    var $rename_table_sql = "sp_rename 'OLDNAME', 'NEWNAME'"; //SQL sentence to rename one table, both
-                                  //OLDNAME and NEWNAME are dinamically replaced
-
-    var $rename_table_extra_code = true; //Does the generator need to add code after table rename
-
-    var $rename_column_extra_code = true; //Does the generator need to add code after field rename
-
-    var $rename_column_sql = "sp_rename 'TABLENAME.OLDFIELDNAME', 'NEWFIELDNAME', 'COLUMN'";
-                                      ///TABLENAME, OLDFIELDNAME and NEWFIELDNAME are dianmically replaced
-
-    var $drop_index_sql = 'DROP INDEX TABLENAME.INDEXNAME'; //SQL sentence to drop one index
-                                                               //TABLENAME, INDEXNAME are dinamically replaced
-
-    var $rename_index_sql = "sp_rename 'TABLENAME.OLDINDEXNAME', 'NEWINDEXNAME', 'INDEX'"; //SQL sentence to rename one index
-                                      //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dinamically replaced
-
-    var $rename_key_sql = null; //SQL sentence to rename one key
-                                          //TABLENAME, OLDKEYNAME, NEWKEYNAME are dinamically replaced
-
-    /**
-     * Creates one new XMLDBmssql
-     */
-    function XMLDBmssql() {
-        parent::XMLDBgenerator();
-        $this->prefix = '';
-        $this->reserved_words = $this->getReservedWords();
-    }
-
-    /**
-     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
-     */
-    function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
-
-        switch ($xmldb_type) {
-            case XMLDB_TYPE_INTEGER:    // From http://msdn.microsoft.com/library/en-us/tsqlref/ts_da-db_7msw.asp?frame=true
-                if (empty($xmldb_length)) {
-                    $xmldb_length = 10;
-                }
-                if ($xmldb_length > 9) {
-                    $dbtype = 'BIGINT';
-                } else if ($xmldb_length > 4) {
-                    $dbtype = 'INTEGER';
-                } else {
-                    $dbtype = 'SMALLINT';
-                }
-                break;
-            case XMLDB_TYPE_NUMBER:
-                $dbtype = $this->number_type;
-                if (!empty($xmldb_length)) {
-                /// 38 is the max allowed
-                    if ($xmldb_length > 38) {
-                        $xmldb_length = 38;
-                    }
-                    $dbtype .= '(' . $xmldb_length;
-                    if (!empty($xmldb_decimals)) {
-                        $dbtype .= ',' . $xmldb_decimals;
-                    }
-                    $dbtype .= ')';
-                }
-                break;
-            case XMLDB_TYPE_FLOAT:
-                $dbtype = 'FLOAT';
-                if (!empty($xmldb_decimals)) {
-                    if ($xmldb_decimals < 6) {
-                        $dbtype = 'REAL';
-                    }
-                }
-                break;
-            case XMLDB_TYPE_CHAR:
-                $dbtype = 'NVARCHAR';
-                if (empty($xmldb_length)) {
-                    $xmldb_length='255';
-                }
-                $dbtype .= '(' . $xmldb_length . ')';
-                break;
-            case XMLDB_TYPE_TEXT:
-                $dbtype = 'NTEXT';
-                break;
-            case XMLDB_TYPE_BINARY:
-                $dbtype = 'IMAGE';
-                break;
-            case XMLDB_TYPE_DATETIME:
-                $dbtype = 'DATETIME';
-                break;
-        }
-        return $dbtype;
-    }
-
-    /**
-     * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
-     */
-    function getEnumExtraSQL ($xmldb_table, $xmldb_field) {
-
-        $sql = 'CONSTRAINT ' . $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'ck');
-        $sql.= ' CHECK (' . $this->getEncQuoted($xmldb_field->getName()) . ' IN (' . implode(', ', $xmldb_field->getEnumValues()) . '))';
-
-        return $sql;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop the field from the table
-     * MSSQL overwrites the standard sentence because it needs to do some extra work dropping the default and
-     * check constraints
-     */
-    function getDropFieldSQL($xmldb_table, $xmldb_field) {
-
-        global $db;
-
-        $results = array();
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Look for any default constraint in this field and drop it
-        if ($defaultname = $this->getDefaultConstraintName($xmldb_table, $xmldb_field)) {
-            $results[] = 'ALTER TABLE ' . $tablename . ' DROP CONSTRAINT ' . $defaultname;
-        }
-
-    /// Look for any check constraint in this field and drop it
-        if ($drop_check = $this->getDropEnumSQL($xmldb_table, $xmldb_field)) {
-            $results = array_merge($results, $drop_check);
-        }
-
-    /// Build the standard alter table drop column
-        $results[] = 'ALTER TABLE ' . $tablename . ' DROP COLUMN ' . $fieldname;
-
-        return $results;
-    }
-
-    /**
-     * Given one correct XMLDBField and the new name, returns the SQL statements
-     * to rename it (inside one array)
-     * MSSQL is special, so we overload the function here. It needs to
-     * drop the constraints BEFORE renaming the field
-     */
-    function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
-
-        $results = array();  //Array where all the sentences will be stored
-
-    /// Although this is checked in ddllib - rename_field() - double check
-    /// that we aren't trying to rename one "id" field. Although it could be
-    /// implemented (if adding the necessary code to rename sequences, defaults,
-    /// triggers... and so on under each getRenameFieldExtraSQL() function, it's
-    /// better to forbide it, mainly because this field is the default PK and
-    /// in the future, a lot of FKs can be pointing here. So, this field, more
-    /// or less, must be considered inmutable!
-        if ($xmldb_field->getName() == 'id') {
-            return array();
-        }
-
-    /// Drop the check constraint if exists
-        if ($xmldb_field->getEnum()) {
-            $results = array_merge($results, $this->getDropEnumSQL($xmldb_table, $xmldb_field));
-        }
-
-    /// Call to standard (parent) getRenameFieldSQL() function
-        $results = array_merge($results, parent::getRenameFieldSQL($xmldb_table, $xmldb_field, $newname));
-
-        return $results;
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on field rename
-     */
-    function getRenameFieldExtraSQL ($xmldb_table, $xmldb_field, $newname) {
-
-        $results = array();
-
-    /// If the field is enum, drop and re-create the check constraint
-        if ($xmldb_field->getEnum()) {
-        /// Drop the current enum (not needed, it has been dropped before for msqql (in getRenameFieldSQL)
-            //$results = array_merge($results, $this->getDropEnumSQL($xmldb_table, $xmldb_field));
-        /// Change field name (over a clone to avoid some potential problems later)
-            $new_xmldb_field = clone($xmldb_field);
-            $new_xmldb_field->setName($newname);
-
-        /// Recreate the enum
-            $results = array_merge($results, $this->getCreateEnumSQL($xmldb_table, $new_xmldb_field));
-        }
-
-        return $results;
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on table rename
-     */
-    function getRenameTableExtraSQL ($xmldb_table, $newname) {
-
-        $results = array();
-
-        $newt = new XMLDBTable($newname); //Temporal table for name calculations
-
-        $oldtablename = $this->getTableName($xmldb_table);
-        $newtablename = $this->getTableName($newt);
-
-    /// Rename all the check constraints in the table
-        $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
-        $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
-
-        if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
-            foreach ($constraints as $constraint) {
-            /// Drop the old constraint
-                $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
-            /// Calculate the new constraint name
-                $newconstraintname = str_replace($oldconstraintprefix, $newconstraintprefix, $constraint->name);
-            /// Add the new constraint
-                $results[] = 'ALTER TABLE ' . $newtablename . ' ADD CONSTRAINT ' . $newconstraintname .
-                             ' CHECK ' . $constraint->description;
-            }
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table
-     */
-    function getAlterFieldSQL($xmldb_table, $xmldb_field) {
-
-        global $db;
-
-        $results = array(); /// To store all the needed SQL commands
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Take a look to field metadata
-        $meta = array_change_key_case($db->MetaColumns($tablename));
-        $metac = $meta[$fieldname];
-        $oldtype = strtolower($metac->type);
-        $oldmetatype = column_type($xmldb_table->getName(), $fieldname);
-        $oldlength = $metac->max_length;
-        $olddecimals = empty($metac->scale) ? null : $metac->scale;
-        $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
-        $olddefault = empty($metac->has_default) ? null : strtok($metac->default_value, ':');
-
-        $typechanged = true;  //By default, assume that the column type has changed
-        $lengthchanged = true;  //By default, assume that the column length has changed
-
-    /// Detect if we are changing the type of the column
-        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && substr($oldmetatype, 0, 1) == 'I') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_NUMBER  && $oldmetatype == 'N') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_FLOAT   && $oldmetatype == 'F') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_CHAR    && substr($oldmetatype, 0, 1) == 'C') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && substr($oldmetatype, 0, 1) == 'X') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_BINARY  && $oldmetatype == 'B')) {
-            $typechanged = false;
-        }
-
-    /// Detect if we are changing the length of the column, not always necessary to drop defaults
-    /// if only the length changes, but it's safe to do it always
-        if ($xmldb_field->getLength() == $oldlength) {
-            $lengthchanged = false;
-        }
-
-    /// If type or length have changed drop the default if exists
-        if ($typechanged || $lengthchanged) {
-            $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field);
-        }
-
-    /// Just prevent default clauses in this type of sentences for mssql and launch the parent one
-        $this->alter_column_skip_default = true;
-        $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field)); // Call parent
-
-    /// Finally, process the default clause to add it back if necessary
-        if ($typechanged || $lengthchanged) {
-            $results = array_merge($results, $this->getCreateDefaultSQL($xmldb_table, $xmldb_field));
-        }
-
-    /// Return results
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to modify the default of the field in the table
-     */
-    function getModifyDefaultSQL($xmldb_table, $xmldb_field) {
-    /// MSSQL is a bit special with default constraints because it implements them as external constraints so
-    /// normal ALTER TABLE ALTER COLUMN don't work to change defaults. Because this, we have this method overloaded here
-
-        $results = array();
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Decide if we are going to create/modify or to drop the default
-        if ($xmldb_field->getDefault() === null) {
-            $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop but, under some circumptances, re-enable
-            if ($this->getDefaultClause($xmldb_field)) { //If getDefaultClause() it must have one default, create it
-                $results = array_merge($results, $this->getCreateDefaultSQL($xmldb_table, $xmldb_field)); //Create/modify
-            }
-        } else {
-            $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop (only if exists)
-            $results = array_merge($results, $this->getCreateDefaultSQL($xmldb_table, $xmldb_field)); //Create/modify
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum 
-     * (usually invoked from getModifyEnumSQL()
-     */
-    function getCreateEnumSQL($xmldb_table, $xmldb_field) {
-    /// All we have to do is to create the check constraint
-        return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
-                     ' ADD ' . $this->getEnumExtraSQL($xmldb_table, $xmldb_field));
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum
-     * (usually invoked from getModifyEnumSQL()
-     */
-    function getDropEnumSQL($xmldb_table, $xmldb_field) {
-    /// Let's introspect to know the real name of the check constraint
-        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
-            $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
-            $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
-        /// All we have to do is to drop the check constraint
-            return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
-                     ' DROP CONSTRAINT ' . $constraint_name);
-        } else { /// Constraint not found. Nothing to do
-            return array();
-        }
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */
-    function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
-    /// MSSQL is a bit special and it requires the corresponding DEFAULT CONSTRAINT to be dropped
-
-        $results = array();
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Now, check if, with the current field attributes, we have to build one default
-        if ($default_clause = $this->getDefaultClause($xmldb_field)) {
-        /// We need to build the default (Moodle) default, so do it
-            $results[] = 'ALTER TABLE ' . $tablename . ' ADD' . $default_clause . ' FOR ' . $fieldname;
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */
-    function getDropDefaultSQL($xmldb_table, $xmldb_field) {
-    /// MSSQL is a bit special and it requires the corresponding DEFAULT CONSTRAINT to be dropped
-
-        $results = array();
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Look for the default contraint and, if found, drop it
-        if ($defaultname = $this->getDefaultConstraintName($xmldb_table, $xmldb_field)) {
-            $results[] = 'ALTER TABLE ' . $tablename . ' DROP CONSTRAINT ' . $defaultname;
-        } 
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, returns the name of its default constraint in DB
-     * or false if not found
-     * This function should be considered internal and never used outside from generator
-     */
-    function getDefaultConstraintName($xmldb_table, $xmldb_field) {
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Look for any default constraint in this field and drop it
-        if ($default = get_record_sql("SELECT id, object_name(cdefault) AS defaultconstraint
-                                         FROM syscolumns
-                                        WHERE id = object_id('{$tablename}')
-                                          AND name = '{$fieldname}'")) {
-            return $default->defaultconstraint;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Given one XMLDBTable returns one array with all the check constrainsts
-     * in the table (fetched from DB)
-     * Optionally the function allows one xmldb_field to be specified in
-     * order to return only the check constraints belonging to one field.
-     * Each element contains the name of the constraint and its description
-     * If no check constraints are found, returns an empty array
-     */
-    function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
-
-        $results = array();
-
-        $tablename = $this->getTableName($xmldb_table);
-
-        if ($constraints = get_records_sql("SELECT o.name, c.text AS description
-                                            FROM sysobjects o,
-                                                 sysobjects p,
-                                                 syscomments c
-                                           WHERE p.id = o.parent_obj
-                                             AND o.id = c.id
-                                             AND o.xtype = 'C'
-                                             AND p.name = '{$tablename}'")) {
-            foreach ($constraints as $constraint) {
-                $results[$constraint->name] = $constraint;
-            }
-        }
-
-    /// Filter by the required field if specified
-        if ($xmldb_field) {
-            $filtered_results = array();
-            $filter = $xmldb_field->getName();
-        /// Lets clean a bit each constraint description, looking for the filtered field
-            foreach ($results as $key => $result) {
-                $description = trim(preg_replace('/[\(\)]/', '',  $result->description));   // Parenthesis out & trim
-                /// description starts by [$filter] assume it's a constraint beloging to the field
-                if (preg_match("/^\[{$filter}\]/i", $description)) {
-                    $filtered_results[$key] = $result;
-                }
-            }
-        /// Assign filtered results to the final results array
-            $results =  $filtered_results;
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
-     * return if such name is currently in use (true) or no (false)
-     * (invoked from getNameForObject()
-     */
-    function isNameInUse($object_name, $type, $table_name) {
-        switch($type) {
-            case 'seq':
-            case 'trg':
-            case 'pk':
-            case 'uk':
-            case 'fk':
-            case 'ck':
-                if ($check = get_records_sql("SELECT name 
-                                              FROM sysobjects 
-                                              WHERE lower(name) = '" . strtolower($object_name) . "'")) {
-                    return true;
-                }
-                break;
-            case 'ix':
-            case 'uix':
-                if ($check = get_records_sql("SELECT name 
-                                              FROM sysindexes
-                                              WHERE lower(name) = '" . strtolower($object_name) . "'")) {
-                    return true;
-                }
-                break;
-        }
-        return false; //No name in use found
-    }
-
-    /**
-     * Returns an array of reserved words (lowercase) for this DB
-     */
-    function getReservedWords() {
-    /// This file contains the reserved words for MSSQL databases
-    /// from http://msdn2.microsoft.com/en-us/library/ms189822.aspx
-        $reserved_words = array (
-            'add', 'all', 'alter', 'and', 'any', 'as', 'asc', 'authorization',
-            'avg', 'backup', 'begin', 'between', 'break', 'browse', 'bulk',
-            'by', 'cascade', 'case', 'check', 'checkpoint', 'close', 'clustered',
-            'coalesce', 'collate', 'column', 'commit', 'committed', 'compute',
-            'confirm', 'constraint', 'contains', 'containstable', 'continue',
-            'controlrow', 'convert', 'count', 'create', 'cross', 'current',
-            'current_date', 'current_time', 'current_timestamp', 'current_user',
-            'cursor', 'database', 'dbcc', 'deallocate', 'declare', 'default', 'delete',
-            'deny', 'desc', 'disk', 'distinct', 'distributed', 'double', 'drop', 'dummy',
-            'dump', 'else', 'end', 'errlvl', 'errorexit', 'escape', 'except', 'exec',
-            'execute', 'exists', 'exit', 'external', 'fetch', 'file', 'fillfactor', 'floppy',
-            'for', 'foreign', 'freetext', 'freetexttable', 'from', 'full', 'function',
-            'goto', 'grant', 'group', 'having', 'holdlock', 'identity', 'identitycol',
-            'identity_insert', 'if', 'in', 'index', 'inner', 'insert', 'intersect', 'into',
-            'is', 'isolation', 'join', 'key', 'kill', 'left', 'level', 'like', 'lineno',
-            'load', 'max', 'min', 'mirrorexit', 'national', 'nocheck', 'nonclustered',
-            'not', 'null', 'nullif', 'of', 'off', 'offsets', 'on', 'once', 'only', 'open',
-            'opendatasource', 'openquery', 'openrowset', 'openxml', 'option', 'or', 'order',
-            'outer', 'over', 'percent', 'perm', 'permanent', 'pipe', 'pivot', 'plan', 'precision',
-            'prepare', 'primary', 'print', 'privileges', 'proc', 'procedure', 'processexit',
-            'public', 'raiserror', 'read', 'readtext', 'reconfigure', 'references',
-            'repeatable', 'replication', 'restore', 'restrict', 'return', 'revoke',
-            'right', 'rollback', 'rowcount', 'rowguidcol', 'rule', 'save', 'schema',
-            'select', 'serializable', 'session_user', 'set', 'setuser', 'shutdown', 'some',
-            'statistics', 'sum', 'system_user', 'table', 'tape', 'temp', 'temporary',
-            'textsize', 'then', 'to', 'top', 'tran', 'transaction', 'trigger', 'truncate',
-            'tsequal', 'uncommitted', 'union', 'unique', 'update', 'updatetext', 'use',
-            'user', 'values', 'varying', 'view', 'waitfor', 'when', 'where', 'while',
-            'with', 'work', 'writetext'
-        );
-        return $reserved_words;
-    }
-}
-
-?>
Index: admin/xmldb/actions/view_structure_sql/view_structure_sql.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/view_structure_sql/view_structure_sql.class.php,v
retrieving revision 1.5
diff -u -r1.5 view_structure_sql.class.php
--- admin/xmldb/actions/view_structure_sql/view_structure_sql.class.php	10 Oct 2007 05:25:31 -0000	1.5
+++ admin/xmldb/actions/view_structure_sql/view_structure_sql.class.php	15 May 2008 21:10:34 -0000
@@ -58,7 +58,8 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB;
+        global $CFG, $XMLDB, $DB;
+        $dbman = $DB->get_manager();
 
     /// Do the job, setting result as needed
     /// Get the dir containing the file
@@ -77,23 +78,6 @@
         }
     /// ADD YOUR CODE HERE
 
-    /// Get parameters
-        $generatorparam = optional_param('generator', null, PARAM_ALPHANUM);
-        if (empty($generatorparam)) {
-            $generatorparam = $CFG->dbtype;
-        }
-
-    /// Calculate list of available SQL generators
-        $plugins = get_list_of_plugins('lib/xmldb/classes/generators');
-        $generators = array();
-        foreach($plugins as $plugin) {
-            $generators[$plugin] = $plugin;
-        }
-    /// Check we have the selected generator
-        if (!in_array($generatorparam, $generators)) {
-            $generatorparam = reset($generators);
-        }
-
         /// The back to edit table button
         $b = ' <p class="centerpara buttons">';
         $b .= '<a href="index.php?action=edit_xml_file&amp;dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '">[' . $this->str['back'] . ']</a>';
@@ -101,15 +85,10 @@
         $o = $b;
 
         $o.= '    <table id="formelements" class="boxaligncenter" cellpadding="5">';
-        $o.= '      <tr><td align="center">' . $this->str['selectdb'];
-
-    /// Show the popup of generators
-        $url = 'index.php?action=view_structure_sql&amp;dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '&amp;generator=';
-        $o.= popup_form($url, $generators, 'selectgenerator', $generatorparam, '', '', '' , true);
-        $o.= '      </td></tr>';
         $o.= '      <tr><td><textarea cols="80" rows="32">';
     /// Get an array of statements
-        if ($starr = $structure->getCreateStructureSQL($generatorparam, $CFG->prefix)) {
+        if ($starr = $DB->get_manager()->generator->getCreateStructureSQL($structure)) {
+            $starr = $dbman->generator->getEndedStatements($starr);
             $sqltext = '';
             foreach ($starr as $st) {
                 $sqltext .= s($st) . "\n\n";
Index: mod/quiz/report/overview/report.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/report/overview/report.php,v
retrieving revision 1.126
diff -u -r1.126 report.php
--- mod/quiz/report/overview/report.php	15 May 2008 13:59:52 -0000	1.126
+++ mod/quiz/report/overview/report.php	15 May 2008 21:11:30 -0000
@@ -306,7 +306,7 @@
         }
 
         // Construct the SQL
-        $select = 'SELECT '.sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).' AS uniqueid, '.
+        $select = 'SELECT '.sql_concat('u.id', '\'#\'', 'COALESCE(qa.attempt, 0)').' AS uniqueid, '.
             ($qmsubselect?$qmsubselect.' AS gradedattempt, ':'').
             'qa.uniqueid AS attemptuniqueid, qa.id AS attempt, u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, '.
             'qa.sumgrades, qa.timefinish, qa.timestart, qa.timefinish - qa.timestart AS duration ';
@@ -350,7 +350,7 @@
 
         
 
-        $countsql = 'SELECT COUNT(DISTINCT('.sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).')) '.$from.$where;
+        $countsql = 'SELECT COUNT(DISTINCT('.sql_concat('u.id', '\'#\'', 'COALESCE(qa.attempt, 0)').')) '.$from.$where;
 
         $sort = $table->get_sql_sort();
         // Fix some wired sorting
Index: admin/xmldb/actions/view_reserved_words/view_reserved_words.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/view_reserved_words/view_reserved_words.class.php,v
retrieving revision 1.5
diff -u -r1.5 view_reserved_words.class.php
--- admin/xmldb/actions/view_reserved_words/view_reserved_words.class.php	10 Oct 2007 05:25:28 -0000	1.5
+++ admin/xmldb/actions/view_reserved_words/view_reserved_words.class.php	15 May 2008 21:10:34 -0000
@@ -63,49 +63,27 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB, $db;
+        global $CFG, $XMLDB, $DB;
 
     /// Calculate list of available SQL generators
-        $plugins = get_list_of_plugins('lib/xmldb/classes/generators');
-        $reserved_words = array();
-        $reserved_words_bydb = array();
-        foreach($plugins as $plugin) {
-            $classname = 'XMLDB' . $plugin;
-            $generator = new $classname();
-            $reserved_words = array_merge($reserved_words, $generator->getReservedWords());
-            $reserved_words_bydb[$plugin] = $generator->getReservedWords();
-        }
-        sort($reserved_words);
-        $reserved_words = array_unique($reserved_words);
+        require("$CFG->libdir/ddl/sql_generator.php");
+        $reserved_words = sql_generator::getAllReservedWords();
 
     /// Now, calculate, looking into current DB (with AdoDB Metadata), which fields are
     /// in the list of reserved words
         $wronguses = array();
-        $dbtables = $db->MetaTables('TABLES');
+        $dbtables = $DB->get_tables();
         if ($dbtables) {
-            foreach ($dbtables as $dbtable) {
-                $table = str_replace($CFG->prefix, '', $dbtable);
-                if (in_array($table, $reserved_words)) {
-                    $list_of_db = array();
-                    foreach ($reserved_words_bydb as $key=>$words) {
-                        if (in_array($table, $words)) {
-                            $list_of_db[] = $key;
-                        }
-                    }
-                    $wronguses[] = $this->str['table'] . ' - ' . $table . ' (' . implode(', ',$list_of_db) . ')';
+            foreach ($dbtables as $table) {
+                if (array_key_exists($table, $reserved_words)) {
+                    $wronguses[] = $this->str['table'] . ' - ' . $table . ' (' . implode(', ',$reserved_words[$table]) . ')';
 
                 }
-                $dbfields = $db->MetaColumns($dbtable);
+                $dbfields = $DB->get_columns($table);
                 if ($dbfields) {
                     foreach ($dbfields as $dbfield) {
-                        if (in_array($dbfield->name, $reserved_words)) {
-                            $list_of_db = array();
-                            foreach ($reserved_words_bydb as $key=>$words) {
-                                if (in_array($dbfield->name, $words)) {
-                                    $list_of_db[] = $key;
-                                }
-                            }
-                            $wronguses[] = $this->str['field'] . ' - ' . $table . '->' . $dbfield->name . ' (' . implode(', ',$list_of_db) . ')';
+                        if (array_key_exists($dbfield->name, $reserved_words)) {
+                            $wronguses[] = $this->str['field'] . ' - ' . $table . '->' . $dbfield->name . ' (' . implode(', ',$reserved_words[$dbfield->name]) . ')';
                         }
                     }
                 }
@@ -135,7 +113,7 @@
         $o.= '    <table id="formelements" class="boxaligncenter" cellpadding="5">';
         $o.= '      <tr><td align="center">' . $this->str['listreservedwords'].'</td></tr>';
         $o.= '      <tr><td><textarea cols="80" rows="32">';
-        $o.= s(implode(', ', $reserved_words));
+        $o.= s(implode(', ', array_keys($reserved_words)));
         $o.= '</textarea></td></tr>';
         $o.= '    </table>';
 
Index: mod/assignment/db/upgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/assignment/db/upgrade.php,v
retrieving revision 1.12
diff -u -r1.12 upgrade.php
--- mod/assignment/db/upgrade.php	1 May 2008 20:37:04 -0000	1.12
+++ mod/assignment/db/upgrade.php	15 May 2008 21:11:22 -0000
@@ -19,7 +19,7 @@
 
 function xmldb_assignment_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
 
     $result = true;
 
@@ -30,9 +30,9 @@
         // change grade typo to text if no grades MDL-13920
         require_once $CFG->dirroot.'/mod/assignment/lib.php';
         // too much debug output
-        $db->debug = false;
+        $DB->set_debug(false);
         assignment_update_grades();
-        $db->debug = true;
+        $DB->set_debug(true);
     }
 
     return $result;
Index: mod/chat/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/chat/lib.php,v
retrieving revision 1.110
diff -u -r1.110 lib.php
--- mod/chat/lib.php	4 Apr 2008 02:54:35 -0000	1.110
+++ mod/chat/lib.php	15 May 2008 21:11:23 -0000
@@ -401,31 +401,25 @@
 }
 
 function chat_get_latest_message($chatid, $groupid=0) {
-/// Efficient way to extract just the latest message
-/// Uses ADOdb directly instead of get_record_sql()
-/// because the LIMIT command causes problems with
-/// the developer debugging in there.
+    global $DB;
 
-    global $db, $CFG;
+    $params = array();
 
     if ($groupid) {
-        $groupselect = " AND (groupid='$groupid' OR groupid='0')";
+        $groupselect = " AND (groupid=? OR groupid=0)";
+        $params[] = $groupid;
     } else {
         $groupselect = "";
     }
 
-    if (!$rs = $db->SelectLimit("SELECT *
-                                 FROM {$CFG->prefix}chat_messages
-                                 WHERE chatid = '$chatid' $groupselect
-                                 ORDER BY timestamp DESC", 1)) {
-        return false;
-    }
-
-    $result = rs_fetch_record($rs);
-    
-    rs_close($rs);
+    $sql = "SELECT *
+              FROM {chat_messages}
+             WHERE chatid = ?
+                   $groupselect
+          ORDER BY timestamp DESC";
+    $params[] = $chatid;
 
-    return $result;
+    return $DB->get_record_sql($sql, $params, true);
 }
 
 
Index: admin/xmldb/actions/check_defaults/check_defaults.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/check_defaults/check_defaults.class.php,v
retrieving revision 1.2
diff -u -r1.2 check_defaults.class.php
--- admin/xmldb/actions/check_defaults/check_defaults.class.php	15 May 2008 15:24:03 -0000	1.2
+++ admin/xmldb/actions/check_defaults/check_defaults.class.php	15 May 2008 21:10:31 -0000
@@ -26,7 +26,7 @@
 
 /// This class will check all the default values existing in the DB
 /// match those specified in the xml specs
-/// and providing one SQL script to fix all them. 
+/// and providing one SQL script to fix all them.
 
 class check_defaults extends XMLDBAction {
 
@@ -76,10 +76,11 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB, $db;
+        global $CFG, $XMLDB, $DB;
 
     /// And we nedd some ddl suff
         require_once ($CFG->libdir . '/ddllib.php');
+        $dbman = $DB->get_manager();
 
     /// Here we'll acummulate all the wrong fields found
         $wrong_fields = array();
@@ -125,10 +126,6 @@
                     }
                 /// Load the XML file
                     $xmldb_file = new XMLDBFile($dbdir->path . '/install.xml');
-                /// Load the needed XMLDB generator
-                    $classname = 'XMLDB' . $CFG->dbtype;
-                    $generator = new $classname();
-                    $generator->setPrefix($CFG->prefix);
 
                 /// Only if the file exists
                     if (!$xmldb_file->fileExists()) {
@@ -142,7 +139,7 @@
                     }
                 /// Arriving here, everything is ok, get the XMLDB structure
                     $structure = $xmldb_file->getStructure();
-//echo "<pre>"; print_r( $structure ); die;
+
                     $o.='    <li>' . str_replace($CFG->dirroot . '/', '', $dbdir->path . '/install.xml');
                 /// Getting tables
                     if ($xmldb_tables = $structure->getTables()) {
@@ -150,14 +147,11 @@
                     /// Foreach table, process its fields
                         foreach ($xmldb_tables as $xmldb_table) {
                         /// Skip table if not exists
-                            if (!table_exists($xmldb_table)) {
+                            if (!$dbman->table_exists($xmldb_table)) {
                                 continue;
                             }
                         /// Fetch metadata from phisical DB. All the columns info.
-                            if ($metacolumns = $db->MetaColumns($CFG->prefix . $xmldb_table->getName())) {
-                                $metacolumns = array_change_key_case($metacolumns, CASE_LOWER);
-// echo "<pre>".$xmldb_table->getName(); print_r( $metacolumns ); die;
-                            } else {
+                            if (!$metacolumns = $DB->get_columns($xmldb_table->getName())) {
                             //// Skip table if no metacolumns is available for it
                                 continue;
                             }
@@ -167,33 +161,32 @@
                             if ($xmldb_fields = $xmldb_table->getFields()) {
                                 $o.='        <ul>';
                                 foreach ($xmldb_fields as $xmldb_field) {
-//echo "<pre>"; print_r( $xmldb_field ); die; 
 
-                                // Get the default value for the field 
-                                $xmldbdefault = $xmldb_field->getDefault();
-                                
-                                /// If the metadata for that column doesn't exist, skip
-                                if (!isset($metacolumns[$xmldb_field->getName()])) {
-                                    continue;
-                                }
+                                    // Get the default value for the field
+                                    $xmldbdefault = $xmldb_field->getDefault();
 
-                                /// To variable for better handling
-                                $metacolumn = $metacolumns[$xmldb_field->getName()];
+                                    /// If the metadata for that column doesn't exist or 'id' field found, skip
+                                    if (!isset($metacolumns[$xmldb_field->getName()]) or $xmldb_field->getName() == 'id') {
+                                        continue;
+                                    }
 
-                                /// Going to check this field in DB
-                                $o.='            <li>' . $this->str['field'] . ': ' . $xmldb_field->getName() . ' ';
+                                    /// To variable for better handling
+                                    $metacolumn = $metacolumns[$xmldb_field->getName()];
 
-                                // get the value of the physical default (or blank if there isn't one)
-                                if ($metacolumn->has_default==1) {
-                                    $physicaldefault = $metacolumn->default_value;
-                                }
-                                else {
-                                    $physicaldefault = '';
-                                }
+                                    /// Going to check this field in DB
+                                    $o.='            <li>' . $this->str['field'] . ': ' . $xmldb_field->getName() . ' ';
 
-                                // there *is* a default and it's wrong
-                                if ($physicaldefault != $xmldbdefault) {
-                                    $info = '['.$this->str['shouldbe']." '$xmldbdefault' ".$this->str['butis'].
+                                    // get the value of the physical default (or blank if there isn't one)
+                                    if ($metacolumn->has_default==1) {
+                                        $physicaldefault = $metacolumn->default_value;
+                                    }
+                                    else {
+                                        $physicaldefault = '';
+                                    }
+
+                                    // there *is* a default and it's wrong
+                                    if ($physicaldefault != $xmldbdefault) {
+                                        $info = '['.$this->str['shouldbe']." '$xmldbdefault' ".$this->str['butis'].
                                         " '$physicaldefault']";
                                         $o.='<font color="red">' . $this->str['wrong'] . " $info</font>";
                                     /// Add the wrong field to the list
@@ -237,9 +230,9 @@
                     $xmldb_field = $obj->field;
                     $physicaldefault = $obj->physicaldefault;
                     $xmldbdefault = $obj->xmldbdefault;
-                     
+
                     // get the alter table command
-                    $sqlarr = $xmldb_table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $xmldb_field, true);
+                    $sqlarr = $dbman->generator->getAlterFieldSQL($xmldb_table, $xmldb_field);
 
                     $r.= '            <li>' . $this->str['table'] . ': ' . $xmldb_table->getName() . '. ' .
                                               $this->str['field'] . ': ' . $xmldb_field->getName() . ', ' .
@@ -247,6 +240,7 @@
                                               $this->str['butis'] . ' ' . "'$physicaldefault'" . '</li>';
                     /// Add to output if we have sentences
                     if ($sqlarr) {
+                        $sqlarr = $dbman->generator->getEndedStatements($sqlarr);
                         $s.= '<code>' . str_replace("\n", '<br />', implode('<br />', $sqlarr)) . '</code><br />';
                     }
                 }
Index: lib/xmldb/classes/generators/XMLDBGenerator.class.php
===================================================================
RCS file: lib/xmldb/classes/generators/XMLDBGenerator.class.php
diff -N lib/xmldb/classes/generators/XMLDBGenerator.class.php
--- lib/xmldb/classes/generators/XMLDBGenerator.class.php	10 Oct 2007 05:25:25 -0000	1.66
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,1224 +0,0 @@
-<?php // $Id: XMLDBGenerator.class.php,v 1.66 2007/10/10 05:25:25 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class represent the base generator class where all the
-/// needed functions to generate proper SQL are defined.
-
-/// The rest of classes will inherit, by default, the same logic.
-/// Functions will be overriden as needed to generate correct SQL.
-
-class XMLDBgenerator {
-
-/// Please, avoid editing this defaults in this base class!
-/// It could change the behaviour of the rest of generators
-/// that, by default, inherit this configuration.
-/// To change any of them, do it in extended classes instead.
-
-    var $quote_string = '"';   // String used to quote names
-
-    var $quote_all    = false; // To decide if we want to quote all the names or only the reserved ones
-
-    var $statement_end = ';'; // String to be automatically added at the end of each statement
-
-    var $integer_to_number = false;  // To create all the integers as NUMBER(x) (also called DECIMAL, NUMERIC...)
-    var $float_to_number   = false;  // To create all the floats as NUMBER(x) (also called DECIMAL, NUMERIC...)
-
-    var $number_type = 'NUMERIC';    // Proper type for NUMBER(x) in this DB
-
-    var $unsigned_allowed = true;    // To define in the generator must handle unsigned information
-    var $default_for_char = null;      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
-
-    var $drop_default_clause_required = false; //To specify if the generator must use some DEFAULT clause to drop defaults
-    var $drop_default_clause = ''; //The DEFAULT clause required to drop defaults
-
-    var $default_after_null = true;  //To decide if the default clause of each field must go after the null clause
-
-    var $specify_nulls = false;  //To force the generator if NULL clauses must be specified. It shouldn't be necessary
-                                 //but some mssql drivers require them or everything is created as NOT NULL :-(
-
-    var $primary_key_name = null; //To force primary key names to one string (null=no force)
-
-    var $primary_keys = true;  // Does the generator build primary keys
-    var $unique_keys = false;  // Does the generator build unique keys
-    var $foreign_keys = false; // Does the generator build foreign keys
-
-    var $drop_primary_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop PKs
-                               // with automatic replace for TABLENAME and KEYNAME
-
-    var $drop_unique_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop UKs
-                               // with automatic replace for TABLENAME and KEYNAME
-
-    var $drop_foreign_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop FKs
-                               // with automatic replace for TABLENAME and KEYNAME
-
-    var $sequence_extra_code = true; //Does the generator need to add extra code to generate the sequence fields
-    var $sequence_name = 'auto_increment'; //Particular name for inline sequences in this generator
-    var $sequence_name_small = false; //Different name for small (4byte) sequences or false if same
-    var $sequence_only = false; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable
-
-    var $enum_inline_code = true; //Does the generator need to add inline code in the column definition
-    var $enum_extra_code = true; //Does the generator need to add extra code to generate code for the enums in the table
-
-    var $add_table_comments  = true;  // Does the generator need to add code for table comments
-
-    var $add_after_clause = false; // Does the generator need to add the after clause for fields
-
-    var $prefix_on_names = true; //Does the generator need to prepend the prefix to all the key/index/sequence/trigger/check names
-
-    var $names_max_length = 30; //Max length for key/index/sequence/trigger/check names (keep 30 for all!)
-
-    var $concat_character = '||'; //Characters to be used as concatenation operator. If not defined
-                                  //MySQL CONCAT function will be used
-
-    var $rename_table_sql = 'ALTER TABLE OLDNAME RENAME TO NEWNAME'; //SQL sentence to rename one table, both
-                                  //OLDNAME and NEWNAME are dinamically replaced
-
-    var $rename_table_extra_code = false; //Does the generator need to add code after table rename
-
-    var $drop_table_sql = 'DROP TABLE TABLENAME'; //SQL sentence to drop one table
-                                  //TABLENAME is dinamically replaced
-
-    var $drop_table_extra_code = false; //Does the generator need to add code after table drop
-
-    var $alter_column_sql = 'ALTER TABLE TABLENAME ALTER COLUMN COLUMNSPECS'; //The SQL template to alter columns
-
-    var $alter_column_skip_default = false; //The generator will skip the default clause on alter columns
-
-    var $alter_column_skip_type = false; //The generator will skip the type clause on alter columns
-
-    var $alter_column_skip_notnull = false; //The generator will skip the null/notnull clause on alter columns
-
-    var $rename_column_sql = 'ALTER TABLE TABLENAME RENAME COLUMN OLDFIELDNAME TO NEWFIELDNAME';
-                                  ///TABLENAME, OLDFIELDNAME and NEWFIELDNAME are dianmically replaced
-
-    var $rename_column_extra_code = false; //Does the generator need to add code after column rename
-
-    var $drop_index_sql = 'DROP INDEX INDEXNAME'; //SQL sentence to drop one index
-                                  //TABLENAME, INDEXNAME are dinamically replaced
-
-    var $rename_index_sql = 'ALTER INDEX OLDINDEXNAME RENAME TO NEWINDEXNAME'; //SQL sentence to rename one index
-                                  //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dinamically replaced
-
-    var $rename_key_sql = 'ALTER TABLE TABLENAME CONSTRAINT OLDKEYNAME RENAME TO NEWKEYNAME'; //SQL sentence to rename one key
-                                  //TABLENAME, OLDKEYNAME, NEWKEYNAME are dinamically replaced
-
-    var $prefix;         // Prefix to be used for all the DB objects
-
-    var $reserved_words; // List of reserved words (in order to quote them properly)
-
-    /**
-     * Creates one new XMLDBGenerator
-     */
-    function XMLDBgenerator() {
-        global $CFG;
-        $this->prefix = '';
-        $this->reserved_words = $this->getReservedWords();
-    }
-
-/// ALL THESE FUNCTION ARE SHARED BY ALL THE XMLDGenerator classes
-
-    /**
-     * Set the prefix
-     */
-    function setPrefix($prefix) {
-        if ($this->prefix_on_names) { // Only if we want prefix on names
-            $this->prefix = $prefix;
-        }
-    }
-
-    /**
-     * Given one XMLDBTable, returns it's correct name, depending of all the parametrization
-     *
-     * @param XMLDBTable table whose name we want
-     * @param boolean to specify if the name must be quoted (if reserved word, only!)
-     * @return string the correct name of the table
-     */
-    function getTableName($xmldb_table, $quoted = true) {
-
-        $prefixtouse = $this->prefix;
-    /// Determinate if this table must have prefix or no
-        if (in_array($xmldb_table->getName(), $this->getTablesWithoutPrefix())) {
-            $prefixtouse = '';
-        }
-    /// Get the name
-        $tablename = $prefixtouse . $xmldb_table->getName();
-    /// Apply quotes conditionally
-        if ($quoted) {
-            $tablename = $this->getEncQuoted($tablename);
-        }
-
-        return $tablename;
-    }
-
-    /**
-     * Given one correct XMLDBTable, returns the SQL statements
-     * to create it (inside one array)
-     */
-    function getCreateTableSQL($xmldb_table) {
-
-        $results = array();  //Array where all the sentences will be stored
-
-    /// Table header
-        $table = 'CREATE TABLE ' . $this->getTableName($xmldb_table) . ' (';
-
-        if (!$xmldb_fields = $xmldb_table->getFields()) {
-            return $results;
-        }
-
-    /// Prevent tables without prefix to be duplicated (part of MDL-6614)
-        if (in_array($xmldb_table->getName(), $this->getTablesWithoutPrefix()) &&
-            table_exists($xmldb_table)) {
-            return $results; // false here would break the install, empty array is better ;-)
-        }
-
-    /// Add the fields, separated by commas
-        foreach ($xmldb_fields as $xmldb_field) {
-            $table .= "\n    " . $this->getFieldSQL($xmldb_field);
-            $table .= ',';
-        }
-    /// Add the keys, separated by commas
-        if ($xmldb_keys = $xmldb_table->getKeys()) {
-            foreach ($xmldb_keys as $xmldb_key) {
-                if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) {
-                    $table .= "\nCONSTRAINT " . $keytext . ',';
-                }
-            /// If the key is XMLDB_KEY_FOREIGN_UNIQUE, create it as UNIQUE too
-                if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE) {
-                ///Duplicate the key
-                    $xmldb_key->setType(XMLDB_KEY_UNIQUE);
-                    if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) {
-                        $table .= "\nCONSTRAINT " . $keytext . ',';
-                    }
-                }
-            }
-        }
-    /// Add enum extra code if needed
-        if ($this->enum_extra_code) {
-        /// Iterate over fields looking for enums
-            foreach ($xmldb_fields as $xmldb_field) {
-                if ($xmldb_field->getEnum()) {
-                    $table .= "\n" . $this->getEnumExtraSQL($xmldb_table, $xmldb_field) . ',';
-                }
-            }
-        }
-    /// Table footer, trim the latest comma
-        $table = trim($table,',');
-        $table .= "\n)";
-
-    /// Add the CREATE TABLE to results
-        $results[] = $table;
-
-    /// Add comments if specified and it exists
-        if ($this->add_table_comments && $xmldb_table->getComment()) {
-            $comment = $this->getCommentSQL ($xmldb_table);
-        /// Add the COMMENT to results
-            $results = array_merge($results, $comment);
-        }
-
-    /// Add the indexes (each one, one statement)
-        if ($xmldb_indexes = $xmldb_table->getIndexes()) {
-            foreach ($xmldb_indexes as $xmldb_index) {
-            ///Only process all this if the index doesn't exist in DB
-                if (!index_exists($xmldb_table, $xmldb_index)) {
-                    if ($indextext = $this->getCreateIndexSQL($xmldb_table, $xmldb_index)) {
-                        $results = array_merge($results, $indextext);
-                    }
-                }
-            }
-        }
-
-    /// Also, add the indexes needed from keys, based on configuration (each one, one statement)
-        if ($xmldb_keys = $xmldb_table->getKeys()) {
-            foreach ($xmldb_keys as $xmldb_key) {
-            /// If we aren't creating the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated 
-            /// automatically by the RDBMS) create the underlying (created by us) index (if doesn't exists)
-                if (!$this->getKeySQL($xmldb_table, $xmldb_key) || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
-                /// Create the interim index   
-                    $index = new XMLDBIndex('anyname');
-                    $index->setFields($xmldb_key->getFields());
-                ///Only process all this if the index doesn't exist in DB
-                    if (!index_exists($xmldb_table, $index)) {
-                        $createindex = false; //By default
-                        switch ($xmldb_key->getType()) {
-                            case XMLDB_KEY_UNIQUE:
-                            case XMLDB_KEY_FOREIGN_UNIQUE:
-                                $index->setUnique(true);
-                                $createindex = true;
-                                break;
-                            case XMLDB_KEY_FOREIGN:
-                                $index->setUnique(false);
-                                $createindex = true;
-                                break;
-                        }
-                        if ($createindex) {
-                            if ($indextext = $this->getCreateIndexSQL($xmldb_table, $index)) {
-                            /// Add the INDEX to the array
-                                $results = array_merge($results, $indextext);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-    /// Add sequence extra code if needed
-        if ($this->sequence_extra_code) {
-        /// Iterate over fields looking for sequences
-            foreach ($xmldb_fields as $xmldb_field) {
-                if ($xmldb_field->getSequence()) {
-                /// returns an array of statements needed to create one sequence
-                    $sequence_sentences = $this->getCreateSequenceSQL($xmldb_table, $xmldb_field);
-                /// Add the SEQUENCE to the array
-                    $results = array_merge($results, $sequence_sentences);
-                }
-            }
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one correct XMLDBIndex, returns the SQL statements
-     * needed to create it (in array)
-     */
-    function getCreateIndexSQL ($xmldb_table, $xmldb_index) {
-
-        $unique = '';
-        $suffix = 'ix';
-        if ($xmldb_index->getUnique()) {
-            $unique = ' UNIQUE';
-            $suffix = 'uix';
-        }
-
-        $index = 'CREATE' . $unique . ' INDEX ';
-        $index .= $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_index->getFields()), $suffix);
-        $index .= ' ON ' . $this->getTableName($xmldb_table);
-        $index .= ' (' . implode(', ', $this->getEncQuoted($xmldb_index->getFields())) . ')';
-
-        return array($index);
-    }
-
-    /**
-     * Given one correct XMLDBField, returns the complete SQL line to create it
-     */
-    function getFieldSQL($xmldb_field, $skip_type_clause = false, $skip_default_clause = false, $skip_notnull_clause = false)  {
-
-    /// First of all, convert integers to numbers if defined
-        if ($this->integer_to_number) {
-            if ($xmldb_field->getType() == XMLDB_TYPE_INTEGER) {
-                $xmldb_field->setType(XMLDB_TYPE_NUMBER);
-            }
-        }
-    /// Same for floats
-        if ($this->float_to_number) {
-            if ($xmldb_field->getType() == XMLDB_TYPE_FLOAT) {
-                $xmldb_field->setType(XMLDB_TYPE_NUMBER);
-            }
-        }
-
-    /// The name
-        $field = $this->getEncQuoted($xmldb_field->getName());
-    /// The type and length only if we don't want to skip it
-        if (!$skip_type_clause) {
-        /// The type and length (if the field isn't enum)
-            if (!$xmldb_field->getEnum() || $this->enum_inline_code == false) {
-                $field .= ' ' . $this->getTypeSQL($xmldb_field->getType(), $xmldb_field->getLength(), $xmldb_field->getDecimals());
-            } else {
-            /// call to custom function
-                $field .= ' ' . $this->getEnumSQL($xmldb_field);
-            }
-        }
-    /// The unsigned if supported
-        if ($this->unsigned_allowed && ($xmldb_field->getType() == XMLDB_TYPE_INTEGER ||
-                                      $xmldb_field->getType() == XMLDB_TYPE_NUMBER ||
-                                      $xmldb_field->getType() == XMLDB_TYPE_FLOAT)) {
-            if ($xmldb_field->getUnsigned()) {
-                $field .= ' unsigned';
-            }
-        }
-    /// Calculate the not null clause
-        $notnull = '';
-    /// Only if we don't want to skip it
-        if (!$skip_notnull_clause) {
-            if ($xmldb_field->getNotNull()) {
-                $notnull = ' NOT NULL';
-            } else {
-                if ($this->specify_nulls) {
-                    $notnull = ' NULL';
-                }
-            }
-        }
-    /// Calculate the default clause
-        if (!$skip_default_clause) { //Only if we don't want to skip it
-            $default = $this->getDefaultClause($xmldb_field);
-        } else {
-            $default = '';
-        }
-    /// Based on default_after_null, set both clauses properly
-        if ($this->default_after_null) {
-            $field .= $notnull . $default;
-        } else {
-            $field .= $default . $notnull;
-        }
-    /// The sequence
-        if ($xmldb_field->getSequence()) {
-            if($xmldb_field->getLength()<=9 && $this->sequence_name_small) {
-                $sequencename=$this->sequence_name_small;
-            } else {
-                $sequencename=$this->sequence_name;
-            }
-            $field .= ' ' . $sequencename;
-            if ($this->sequence_only) {
-            /// We only want the field name and sequence name to be printed
-            /// so, calculate it and return
-                return $this->getEncQuoted($xmldb_field->getName()) . ' ' . $sequencename;
-            }
-        }
-        return $field;
-    }
-
-    /**
-     * Given one correct XMLDBKey, returns its specs
-     */
-    function getKeySQL ($xmldb_table, $xmldb_key) {
-
-        $key = '';
-
-        switch ($xmldb_key->getType()) {
-            case XMLDB_KEY_PRIMARY:
-                if ($this->primary_keys) {
-                    if ($this->primary_key_name !== null) {
-                        $key = $this->getEncQuoted($this->primary_key_name);
-                    } else {
-                        $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'pk');
-                    }
-                    $key .= ' PRIMARY KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')';
-                }
-                break;
-            case XMLDB_KEY_UNIQUE:
-                if ($this->unique_keys) {
-                    $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'uk');
-                    $key .= ' UNIQUE (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')';
-                }
-                break;
-            case XMLDB_KEY_FOREIGN:
-            case XMLDB_KEY_FOREIGN_UNIQUE:
-                if ($this->foreign_keys) {
-                    $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'fk');
-                    $key .= ' FOREIGN KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')';
-                    $key .= ' REFERENCES ' . $this->getEncQuoted($this->prefix . $xmldb_key->getRefTable());
-                    $key .= ' (' . implode(', ', $this->getEncQuoted($xmldb_key->getRefFields())) . ')';
-                }
-                break;
-        }
-
-        return $key;
-    }
-
-    /**
-     * Give one XMLDBField, returns the correct "default value" for the current configuration
-     */
-    function getDefaultValue ($xmldb_field) {
-
-        $default = null;
-
-        if ($xmldb_field->getDefault() !== NULL) {
-            if ($xmldb_field->getType() == XMLDB_TYPE_CHAR ||
-                $xmldb_field->getType() == XMLDB_TYPE_TEXT) {
-                    $default = "'" . addslashes($xmldb_field->getDefault()) . "'";
-            } else {
-                $default = $xmldb_field->getDefault();
-            }
-        } else {
-        /// We force default '' for not null char columns without proper default
-        /// some day this should be out!
-            if ($this->default_for_char !== NULL &&
-                $xmldb_field->getType() == XMLDB_TYPE_CHAR &&
-                $xmldb_field->getNotNull()) {
-                $default = "'" . $this->default_for_char . "'";
-            } else {
-            /// If the DB requires to explicity define some clause to drop one default, do it here
-            /// never applying defaults to TEXT and BINARY fields
-                if ($this->drop_default_clause_required &&
-                    $xmldb_field->getType() != XMLDB_TYPE_TEXT &&
-                    $xmldb_field->getType() != XMLDB_TYPE_BINARY && !$xmldb_field->getNotNull()) {
-                    $default = $this->drop_default_clause;
-                }
-            }
-        }
-        return $default;
-    }
-
-    /**
-     * Given one XMLDBField, returns the correct "default clause" for the current configuration
-     */
-    function getDefaultClause ($xmldb_field) {
-
-        $defaultvalue = $this->getDefaultValue ($xmldb_field);
-
-        if ($defaultvalue !== null) {
-            return ' DEFAULT ' . $defaultvalue;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Given one correct XMLDBTable and the new name, returns the SQL statements
-     * to rename it (inside one array)
-     */
-    function getRenameTableSQL($xmldb_table, $newname) {
-
-        $results = array();  //Array where all the sentences will be stored
-
-        $newt = new XMLDBTable($newname); //Temporal table for name calculations
-
-        $rename = str_replace('OLDNAME', $this->getTableName($xmldb_table), $this->rename_table_sql);
-        $rename = str_replace('NEWNAME', $this->getTableName($newt), $rename);
-
-        $results[] = $rename;
-
-    /// Call to getRenameTableExtraSQL() if $rename_table_extra_code is enabled. It will add sequence regeneration code.
-        if ($this->rename_table_extra_code) {
-            $extra_sentences = $this->getRenameTableExtraSQL($xmldb_table, $newname);
-            $results = array_merge($results, $extra_sentences);
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one correct XMLDBTable and the new name, returns the SQL statements
-     * to drop it (inside one array)
-     */
-    function getDropTableSQL($xmldb_table) {
-
-        $results = array();  //Array where all the sentences will be stored
-
-        $drop = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->drop_table_sql);
-
-        $results[] = $drop;
-
-    /// call to getDropTableExtraSQL() if $drop_table_extra_code is enabled. It will add sequence/trigger drop code.
-        if ($this->drop_table_extra_code) {
-            $extra_sentences = $this->getDropTableExtraSQL($xmldb_table);
-            $results = array_merge($results, $extra_sentences);
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add the field to the table
-     */
-    function getAddFieldSQL($xmldb_table, $xmldb_field) {
-
-        $results = array();
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-
-    /// Build the standard alter table add
-        $altertable = 'ALTER TABLE ' . $tablename . ' ADD ' . 
-                           $this->getFieldSQL($xmldb_field, $this->alter_column_skip_type,
-                                                            $this->alter_column_skip_default,
-                                                            $this->alter_column_skip_notnull);
-    /// Add the after clause if necesary
-        if ($this->add_after_clause && $xmldb_field->getPrevious()) {
-            $altertable .= ' after ' . $this->getEncQuoted($xmldb_field->getPrevious());
-        }
-        $results[] = $altertable;
-
-    /// If the DB has extra enum code
-        if ($this->enum_extra_code) {
-        /// If it's enum add the extra code
-            if ($xmldb_field->getEnum()) {
-                $results[] = 'ALTER TABLE ' . $tablename . ' ADD ' . $this->getEnumExtraSQL($xmldb_table, $xmldb_field);
-            }
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop the field from the table
-     */
-    function getDropFieldSQL($xmldb_table, $xmldb_field) {
-
-        $results = array();
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Build the standard alter table drop
-        $results[] = 'ALTER TABLE ' . $tablename . ' DROP COLUMN ' . $fieldname;
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table
-     */
-    function getAlterFieldSQL($xmldb_table, $xmldb_field) {
-
-        $results = array();
-
-    /// Always specify NULLs in alter fields because we can change not nulls to nulls
-        $this->specify_nulls = true;
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Build de alter sentence using the alter_column_sql template
-        $alter = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->alter_column_sql);
-        $alter = str_replace('COLUMNSPECS', $this->getFieldSQL($xmldb_field, $this->alter_column_skip_type,
-                                                                             $this->alter_column_skip_default,
-                                                                             $this->alter_column_skip_notnull), $alter);
-
-    /// Add the after clause if necesary
-        if ($this->add_after_clause && $xmldb_field->getPrevious()) {
-            $alter .= ' after ' . $this->getEncQuoted($xmldb_field->getPrevious());
-        }
-
-    /// Build the standard alter table modify
-        $results[] = $alter;
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to modify the enum of the field in the table
-     */
-    function getModifyEnumSQL($xmldb_table, $xmldb_field) {
-
-        $results = array();
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Decide if we are going to create or to drop the enum (based exclusively in the values passed!)
-        if (!$xmldb_field->getEnum()) {
-            $results = $this->getDropEnumSQL($xmldb_table, $xmldb_field); //Drop
-        } else {
-            $results = $this->getCreateEnumSQL($xmldb_table, $xmldb_field); //Create/modify
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to modify the default of the field in the table
-     */
-    function getModifyDefaultSQL($xmldb_table, $xmldb_field) {
-
-        $results = array();
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Decide if we are going to create/modify or to drop the default
-        if ($xmldb_field->getDefault() === null) {
-            $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop
-        } else {
-            $results = $this->getCreateDefaultSQL($xmldb_table, $xmldb_field); //Create/modify
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one correct XMLDBField and the new name, returns the SQL statements
-     * to rename it (inside one array)
-     */
-    function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
-
-        $results = array();  //Array where all the sentences will be stored
-
-    /// Although this is checked in ddllib - rename_field() - double check
-    /// that we aren't trying to rename one "id" field. Although it could be
-    /// implemented (if adding the necessary code to rename sequences, defaults,
-    /// triggers... and so on under each getRenameFieldExtraSQL() function, it's
-    /// better to forbide it, mainly because this field is the default PK and
-    /// in the future, a lot of FKs can be pointing here. So, this field, more
-    /// or less, must be considered inmutable!
-        if ($xmldb_field->getName() == 'id') {
-            return array();
-        }
-
-        $rename = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_column_sql);
-        $rename = str_replace('OLDFIELDNAME', $this->getEncQuoted($xmldb_field->getName()), $rename);
-        $rename = str_replace('NEWFIELDNAME', $this->getEncQuoted($newname), $rename);
-
-        $results[] = $rename;
-
-    /// Call to getRenameFieldExtraSQL() if $rename_column_extra_code is enabled (will add some required sentences)
-        if ($this->rename_column_extra_code) {
-            $extra_sentences = $this->getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname);
-            $results = array_merge($results, $extra_sentences);
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBKey, return the SQL statements needded to add the key to the table
-     * note that undelying indexes will be added as parametrised by $xxxx_keys and $xxxx_index parameters
-     */
-    function getAddKeySQL($xmldb_table, $xmldb_key) {
-
-        $results = array();
-
-    /// Just use the CreateKeySQL function
-        if ($keyclause = $this->getKeySQL($xmldb_table, $xmldb_key)) {
-            $key = 'ALTER TABLE ' . $this->getTableName($xmldb_table) .
-               ' ADD CONSTRAINT ' . $keyclause;
-            $results[] = $key;
-        }
-
-    /// If we aren't creating the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated 
-    /// automatically by the RDBMS) create the underlying (created by us) index (if doesn't exists)
-        if (!$keyclause || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
-        /// Only if they don't exist
-            if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN) {  ///Calculate type of index based on type ok key
-                $indextype = XMLDB_INDEX_NOTUNIQUE;
-            } else {
-                $indextype = XMLDB_INDEX_UNIQUE;
-            }
-            $xmldb_index = new XMLDBIndex('anyname');
-            $xmldb_index->setAttributes($indextype, $xmldb_key->getFields());
-            if (!index_exists($xmldb_table, $xmldb_index)) {
-                $results = array_merge($results, $this->getAddIndexSQL($xmldb_table, $xmldb_index));
-            }
-        }
-
-    /// If the key is XMLDB_KEY_FOREIGN_UNIQUE, create it as UNIQUE too
-        if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && $this->unique_keys) {
-        ///Duplicate the key
-            $xmldb_key->setType(XMLDB_KEY_UNIQUE);
-            $results = array_merge($results, $this->getAddKeySQL($xmldb_table, $xmldb_key));
-        }
-        
-    /// Return results
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to drop the index from the table
-     */
-    function getDropKeySQL($xmldb_table, $xmldb_key) {
-
-        $results = array();
-
-    /// Get the key name (note that this doesn't introspect DB, so could cause some problems sometimes!)
-    /// TODO: We'll need to overwrite the whole getDropKeySQL() method inside each DB to do the proper queries
-    /// against the dictionary or require ADOdb to support it or change the find_key_name() method to
-    /// perform DB introspection directly. But, for now, as we aren't going to enable referential integrity
-    /// it won't be a problem at all
-        $dbkeyname = find_key_name($xmldb_table, $xmldb_key);
-
-    /// Only if such type of key generation is enabled
-        $dropkey = false;
-        switch ($xmldb_key->getType()) {
-            case XMLDB_KEY_PRIMARY:
-                if ($this->primary_keys) {
-                    $template = $this->drop_primary_key;
-                    $dropkey = true;
-                }
-                break;
-            case XMLDB_KEY_UNIQUE:
-                if ($this->unique_keys) {
-                    $template = $this->drop_unique_key;
-                    $dropkey = true;
-                }
-                break;
-            case XMLDB_KEY_FOREIGN_UNIQUE:
-            case XMLDB_KEY_FOREIGN:
-                if ($this->foreign_keys) {
-                    $template = $this->drop_foreign_key;
-                    $dropkey = true;
-                }
-                break;
-        }
-    /// If we have decided to drop the key, let's do it
-        if ($dropkey) {
-        /// Replace TABLENAME, CONSTRAINTTYPE and KEYNAME as needed
-            $dropsql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $template);
-            $dropsql = str_replace('KEYNAME', $dbkeyname, $dropsql);
-
-            $results[] = $dropsql;
-        }
-
-    /// If we aren't dropping the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated 
-    /// automatically by the RDBMS) drop the underlying (created by us) index (if exists)
-        if (!$dropkey || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
-        /// Only if they exist
-            $xmldb_index = new XMLDBIndex('anyname');
-            $xmldb_index->setAttributes(XMLDB_INDEX_UNIQUE, $xmldb_key->getFields());
-            if (index_exists($xmldb_table, $xmldb_index)) {
-                $results = array_merge($results, $this->getDropIndexSQL($xmldb_table, $xmldb_index));
-            }
-        }
-
-    /// If the key is XMLDB_KEY_FOREIGN_UNIQUE, drop the UNIQUE too
-        if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && $this->unique_keys) {
-        ///Duplicate the key
-            $xmldb_key->setType(XMLDB_KEY_UNIQUE);
-            $results = array_merge($results, $this->getDropKeySQL($xmldb_table, $xmldb_key));
-        }
-        
-    /// Return results
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBKey, return the SQL statements needded to rename the key in the table
-     * Experimental! Shouldn't be used at all!
-     */
-
-    function getRenameKeySQL($xmldb_table, $xmldb_key, $newname) {
-
-        $results = array();
-
-    /// Get the real key name
-        $dbkeyname = find_key_name($xmldb_table, $xmldb_key);
-
-    /// Check we are really generating this type of keys
-        if (($xmldb_key->getType() == XMLDB_KEY_PRIMARY && !$this->primary_keys) ||
-            ($xmldb_key->getType() == XMLDB_KEY_UNIQUE && !$this->unique_keys) ||
-            ($xmldb_key->getType() == XMLDB_KEY_FOREIGN && !$this->foreign_keys) ||
-            ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && !$this->unique_keys && !$this->foreign_keys)) {
-        /// We aren't generating this type of keys, delegate to child indexes
-            $xmldb_index = new XMLDBIndex($xmldb_key->getName());
-            $xmldb_index->setFields($xmldb_key->getFields());
-            return $this->getRenameIndexSQL($xmldb_table, $xmldb_index, $newname);
-        }
-
-    /// Arrived here so we are working with keys, lets rename them
-    /// Replace TABLENAME and KEYNAME as needed
-        $renamesql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_key_sql);
-        $renamesql = str_replace('OLDKEYNAME', $dbkeyname, $renamesql);
-        $renamesql = str_replace('NEWKEYNAME', $newname, $renamesql);
-
-    /// Some DB doesn't support key renaming so this can be empty
-        if ($renamesql) {
-            $results[] = $renamesql;
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to add the index to the table
-     */
-    function getAddIndexSQL($xmldb_table, $xmldb_index) {
-
-    /// Just use the CreateIndexSQL function
-        return $this->getCreateIndexSQL($xmldb_table, $xmldb_index);
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to drop the index from the table
-     */
-    function getDropIndexSQL($xmldb_table, $xmldb_index) {
-
-        $results = array();
-
-    /// Get the real index name
-        $dbindexname = find_index_name($xmldb_table, $xmldb_index);
-
-    /// Replace TABLENAME and INDEXNAME as needed
-        $dropsql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->drop_index_sql);
-        $dropsql = str_replace('INDEXNAME', $dbindexname, $dropsql);
-
-        $results[] = $dropsql;
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to rename the index in the table
-     * Experimental! Shouldn't be used at all!
-     */
-
-    function getRenameIndexSQL($xmldb_table, $xmldb_index, $newname) {
-
-        $results = array();
-
-    /// Get the real index name
-        $dbindexname = find_index_name($xmldb_table, $xmldb_index);
-
-    /// Replace TABLENAME and INDEXNAME as needed
-        $renamesql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_index_sql);
-        $renamesql = str_replace('OLDINDEXNAME', $dbindexname, $renamesql);
-        $renamesql = str_replace('NEWINDEXNAME', $newname, $renamesql);
-
-    /// Some DB doesn't support index renaming (MySQL) so this can be empty
-        if ($renamesql) {
-            $results[] = $renamesql;
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given three strings (table name, list of fields (comma separated) and suffix),
-     * create the proper object name quoting it if necessary.
-     *
-     * IMPORTANT: This function must be used to CALCULATE NAMES of objects TO BE CREATED,
-     *            NEVER TO GUESS NAMES of EXISTING objects!!!
-     */
-    function getNameForObject($tablename, $fields, $suffix='') {
-
-        $name = '';
-
-    /// Implement one basic cache to avoid object name duplication
-    /// and to speed up repeated queries for the same objects
-        if (!isset($used_names)) {
-            static $used_names = array();
-        }
-
-    /// If this exact object has been requested, return it
-        if (array_key_exists($tablename.'-'.$fields.'-'.$suffix, $used_names)) {
-            return $used_names[$tablename.'-'.$fields.'-'.$suffix];
-        }
-
-    /// Use standard naming. See http://docs.moodle.org/en/XMLDB_key_and_index_naming
-        $tablearr = explode ('_', $tablename);
-        foreach ($tablearr as $table) {
-            $name .= substr(trim($table),0,4);
-        }
-        $name .= '_';
-        $fieldsarr = explode (',', $fields);
-        foreach ($fieldsarr as $field) {
-            $name .= substr(trim($field),0,3);
-        }
-    /// Prepend the prefix
-        $name = $this->prefix . $name;
-
-        $name = substr(trim($name), 0, $this->names_max_length - 1 - strlen($suffix)); //Max names_max_length
-
-    /// Add the suffix
-        $namewithsuffix = $name;
-        if ($suffix) {
-            $namewithsuffix = $namewithsuffix . '_' . $suffix;
-        }
-
-    /// If the calculated name is in the cache, or if we detect it by introspecting the DB let's modify if
-        if (in_array($namewithsuffix, $used_names) || $this->isNameInUse($namewithsuffix, $suffix, $tablename)) {
-            $counter = 2;
-        /// If have free space, we add 2
-            if (strlen($namewithsuffix) < $this->names_max_length) {
-                $newname = $name . $counter;
-        /// Else replace the last char by 2
-            } else {
-                $newname = substr($name, 0, strlen($name)-1) . $counter;
-            }
-            $newnamewithsuffix = $newname;
-            if ($suffix) {
-                $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix;
-            }
-        /// Now iterate until not used name is found, incrementing the counter
-            while (in_array($newnamewithsuffix, $used_names) || $this->isNameInUse($newnamewithsuffix, $suffix, $tablename)) {
-                $counter++;
-                $newname = substr($name, 0, strlen($newname)-1) . $counter;
-                $newnamewithsuffix = $newname;
-                if ($suffix) {
-                    $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix;
-                }
-            }
-            $namewithsuffix = $newnamewithsuffix;
-        }
-
-    /// Add the name to the cache
-        $used_names[$tablename.'-'.$fields.'-'.$suffix] = $namewithsuffix;
-
-    /// Quote it if necessary (reserved words)
-        $namewithsuffix = $this->getEncQuoted($namewithsuffix);
-
-        return $namewithsuffix;
-    }
-
-    /**
-     * Given any string (or one array), enclose it by the proper quotes
-     * if it's a reserved word
-     */
-    function getEncQuoted($input) {
-
-        if (is_array($input)) {
-            foreach ($input as $key=>$content) {
-                $input[$key] = $this->getEncQuoted($content);
-            }
-            return $input;
-        } else {
-        /// Always lowercase
-            $input = strtolower($input);
-        /// if reserved or quote_all, quote it
-            if ($this->quote_all || in_array($input, $this->reserved_words)) {
-                $input = $this->quote_string . $input . $this->quote_string;
-            }
-            return $input;
-        }
-    }
-
-    /**
-     * Given one XMLDB Statement, build the needed SQL insert sentences to execute it
-     */
-    function getExecuteInsertSQL($statement) {
-
-         $results = array();  //Array where all the sentences will be stored
-
-         if ($sentences = $statement->getSentences()) {
-             foreach ($sentences as $sentence) {
-             /// Get the list of fields
-                 $fields = $statement->getFieldsFromInsertSentence($sentence);
-             /// Get the values of fields
-                 $values = $statement->getValuesFromInsertSentence($sentence);
-             /// Look if we have some CONCAT value and transform it dinamically
-                 foreach($values as $key => $value) {
-                 /// Trim single quotes
-                     $value = trim($value,"'");
-                     if (stristr($value, 'CONCAT') !== false){
-                     /// Look for data between parentesis
-                         preg_match("/CONCAT\s*\((.*)\)$/is", trim($value), $matches);
-                         if (isset($matches[1])) {
-                             $part = $matches[1];
-                         /// Convert the comma separated string to an array
-                             $arr = XMLDBObject::comma2array($part);
-                             if ($arr) {
-                                 $value = $this->getConcatSQL($arr);
-                             }
-                         }
-                     }
-                 /// Values to be sent to DB must be properly escaped
-                     $value = addslashes($value);
-                 /// Back trimmed quotes
-                     $value = "'" . $value . "'";
-                 /// Back to the array
-                     $values[$key] = $value;
-                 }
-
-             /// Iterate over fields, escaping them if necessary
-                 foreach($fields as $key => $field) {
-                     $fields[$key] = $this->getEncQuoted($field);
-                 }
-             /// Build the final SQL sentence and add it to the array of results
-             $sql = 'INSERT INTO ' . $this->getEncQuoted($this->prefix . $statement->getTable()) .
-                         '(' . implode(', ', $fields) . ') ' .
-                         'VALUES (' . implode(', ', $values) . ')';
-                 $results[] = $sql;
-             }
-
-         }
-         return $results;
-    }
-
-    /**
-     * Given one array of elements, build de proper CONCAT expresion, based
-     * in the $concat_character setting. If such setting is empty, then
-     * MySQL's CONCAT function will be used instead
-     */
-    function getConcatSQL($elements) {
-
-    /// Replace double quoted elements by single quotes
-        foreach($elements as $key => $element) {
-            $element = trim($element);
-            if (substr($element, 0, 1) == '"' &&
-                substr($element, -1, 1) == '"') {
-                    $elements[$key] = "'" . trim($element, '"') . "'";
-            }
-        }
-
-    /// Now call the standard sql_concat() DML function
-        return call_user_func_array('sql_concat', $elements);
-    }
-
-    /**
-     * Given one string (or one array), ends it with statement_end
-     */
-    function getEndedStatements ($input) {
-
-        if (is_array($input)) {
-            foreach ($input as $key=>$content) {
-                $input[$key] = $this->getEndedStatements($content);
-            }
-            return $input;
-        } else {
-            $input = trim($input) . $this->statement_end;
-            return $input;
-        }
-    }
-
-    /**
-     * Returns the name (string) of the sequence used in the table for the autonumeric pk
-     * Only some DB have this implemented
-     */
-    function getSequenceFromDB($xmldb_table) {
-        return false;
-    }
-
-    /**
-     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
-     * return if such name is currently in use (true) or no (false)
-     * (MySQL requires the whole XMLDBTable object to be specified, so we add it always)
-     * (invoked from getNameForObject()
-     * Only some DB have this implemented
-     */
-    function isNameInUse($object_name, $type, $table_name) {
-        return false; //For generators not implementing introspecion, 
-                      //we always return with the name being free to be used
-    }
-
-
-/// ALL THESE FUNCTION MUST BE CUSTOMISED BY ALL THE XMLDGenerator classes
-
-    /**
-     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
-     */
-    function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
-        return 'code for type(precision) goes to function getTypeSQL()';
-    }
-
-    /**
-     * Given one XMLDB Field, return its enum SQL to be added inline with the column definition
-     */
-    function getEnumSQL ($xmldb_field) {
-        return 'code for inline enum declaration goes to function getEnumSQL(). Can be disabled with enum_inline_code=false';
-    }
-
-    /**
-     * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
-     */
-    function getEnumExtraSQL ($xmldb_table, $xmldb_field) {
-        return 'Code for extra enum SQL goes to getEnumExtraSQL(). Can be disabled with enum_extra_code=false';
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on field rename
-     */
-    function getRenameFieldExtraSQL ($xmldb_table, $xmldb_field) {
-        return array('Code for field rename goes to getRenameFieldExtraSQL(). Can be disabled with rename_column_extra_code=false;');
-    }
-
-    /**
-     * Returns the code (array of statements) needed
-     * to create one sequence for the xmldb_table and xmldb_field passes
-     */
-    function getCreateSequenceSQL ($xmldb_table, $xmldb_field) {
-        return array('Code for extra sequence SQL goes to getCreateSequenceSQL(). Can be disabled with sequence_extra_code=false');
-    }
-
-    /**
-     * Returns the code (array of statements) needed to add one comment to the table
-     */
-    function getCommentSQL ($xmldb_table) {
-        return array('Code for table comment goes to getCommentSQL(). Can be disabled with add_table_comments=false;');
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on table rename
-     */
-    function getRenameTableExtraSQL ($xmldb_table) {
-        return array('Code for table rename goes to getRenameTableExtraSQL(). Can be disabled with rename_table_extra_code=false;');
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on table drop
-     */
-    function getDropTableExtraSQL ($xmldb_table) {
-        return array('Code for table drop goes to getDropTableExtraSQL(). Can be disabled with drop_table_extra_code=false;');
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum 
-     * (usually invoked from getModifyEnumSQL()
-     */
-    function getDropEnumSQL($xmldb_table, $xmldb_field) {
-        return array('Code to drop one enum goes to getDropEnumSQL()');
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add its enum 
-     * (usually invoked from getModifyEnumSQL()
-     */
-    function getCreateEnumSQL($xmldb_table, $xmldb_field) {
-        return array('Code to create one enum goes to getCreateEnumSQL()');
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */
-    function getDropDefaultSQL($xmldb_table, $xmldb_field) {
-        return array('Code to drop one default goes to getDropDefaultSQL()');
-    }
-
-    /**
-     * Given one XMLDBTable and one optional XMLDBField, return one array with all the check
-     * constrainst found for that table (or field). Must exist for each DB supported.
-     * (usually invoked from find_check_constraint_name)
-     */
-    function getCheckConstraintsFromDB($xmldb_table, $xmldb_field=null) {
-        return array('Code to fetch check constraints goes to getCheckConstraintsFromDB()');
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */
-    function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
-        return array('Code to create one default goes to getCreateDefaultSQL()');
-    }
-
-    /**
-     * Returns an array of reserved words (lowercase) for this DB
-     * You MUST provide the real list for each DB inside every XMLDB class
-     */
-    function getReservedWords() {
-    /// Some well-know reserved words
-        $reserved_words = array (
-            'user', 'scale', 'type', 'comment', 'view', 'value', 'table', 'index', 'key', 'sequence', 'trigger'
-        );
-        return $reserved_words;
-    }
-
-    /**
-     * Returns an array of tables to be built without prefix (lowercase)
-     * It's enough to keep updated here this function.
-     */
-    function getTablesWithoutPrefix() {
-    /// Some well-known tables to be created without prefix
-        $tables = array (
-            'adodb_logsql'
-        );
-        return $tables;
-    }
-}
-
-?>
Index: lib/xmldb/classes/generators/postgres7/postgres7.class.php
===================================================================
RCS file: lib/xmldb/classes/generators/postgres7/postgres7.class.php
diff -N lib/xmldb/classes/generators/postgres7/postgres7.class.php
--- lib/xmldb/classes/generators/postgres7/postgres7.class.php	10 Oct 2007 05:25:28 -0000	1.36
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,574 +0,0 @@
-<?php // $Id: postgres7.class.php,v 1.36 2007/10/10 05:25:28 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class generate SQL code to be used against PostgreSQL
-/// It extends XMLDBgenerator so everything can be
-/// overriden as needed to generate correct SQL.
-
-class XMLDBpostgres7 extends XMLDBgenerator {
-
-/// Only set values that are different from the defaults present in XMLDBgenerator
-
-    var $number_type = 'NUMERIC';    // Proper type for NUMBER(x) in this DB
-
-    var $unsigned_allowed = false;    // To define in the generator must handle unsigned information
-    var $default_for_char = '';      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
-
-    var $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
-    var $sequence_name = 'BIGSERIAL'; //Particular name for inline sequences in this generator
-    var $sequence_name_small = 'SERIAL'; //Particular name for inline sequences in this generator
-    var $sequence_only = true; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable
-
-    var $rename_table_extra_code = true; //Does the generator need to add code after table rename
-
-    var $rename_column_extra_code = true; //Does the generator need to add code after column rename
-
-    var $enum_inline_code = false; //Does the generator need to add inline code in the column definition
-
-    var $rename_index_sql = 'ALTER TABLE OLDINDEXNAME RENAME TO NEWINDEXNAME'; //SQL sentence to rename one index
-                                      //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dinamically replaced
-
-    var $rename_key_sql = null; //SQL sentence to rename one key (PostgreSQL doesn't support this!)
-                                          //TABLENAME, OLDKEYNAME, NEWKEYNAME are dinamically replaced
-
-    /**
-     * Creates one new XMLDBpostgres7
-     */
-    function XMLDBpostgres7() {
-        parent::XMLDBgenerator();
-        $this->prefix = '';
-        $this->reserved_words = $this->getReservedWords();
-    }
-
-    /**
-     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
-     */
-    function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
-
-        switch ($xmldb_type) {
-            case XMLDB_TYPE_INTEGER:    // From http://www.postgresql.org/docs/7.4/interactive/datatype.html
-                if (empty($xmldb_length)) {
-                    $xmldb_length = 10;
-                }
-                if ($xmldb_length > 9) {
-                    $dbtype = 'BIGINT';
-                } else if ($xmldb_length > 4) {
-                    $dbtype = 'INTEGER';
-                } else {
-                    $dbtype = 'SMALLINT';
-                }
-                break;
-            case XMLDB_TYPE_NUMBER:
-                $dbtype = $this->number_type;
-                if (!empty($xmldb_length)) {
-                    $dbtype .= '(' . $xmldb_length;
-                    if (!empty($xmldb_decimals)) {
-                        $dbtype .= ',' . $xmldb_decimals;
-                    }
-                    $dbtype .= ')';
-                }
-                break;
-            case XMLDB_TYPE_FLOAT:
-                $dbtype = 'DOUBLE PRECISION';
-                if (!empty($xmldb_decimals)) {
-                    if ($xmldb_decimals < 6) {
-                        $dbtype = 'REAL';
-                    }
-                }
-                break;
-            case XMLDB_TYPE_CHAR:
-                $dbtype = 'VARCHAR';
-                if (empty($xmldb_length)) {
-                    $xmldb_length='255';
-                }
-                $dbtype .= '(' . $xmldb_length . ')';
-                break;
-            case XMLDB_TYPE_TEXT:
-                $dbtype = 'TEXT';
-                break;
-            case XMLDB_TYPE_BINARY:
-                $dbtype = 'BYTEA';
-                break;
-            case XMLDB_TYPE_DATETIME:
-                $dbtype = 'TIMESTAMP';
-                break;
-        }
-        return $dbtype;
-    }
-
-    /**
-     * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
-     */
-    function getEnumExtraSQL ($xmldb_table, $xmldb_field) {
-
-        $sql = 'CONSTRAINT ' . $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'ck');
-        $sql.= ' CHECK (' . $this->getEncQuoted($xmldb_field->getName()) . ' IN (' . implode(', ', $xmldb_field->getEnumValues()) . '))';
-
-        return $sql;
-    }
-
-    /**
-     * Returns the code (in array) needed to add one comment to the table
-     */
-    function getCommentSQL ($xmldb_table) {
-
-        $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
-        $comment.= " IS '" . addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
-
-        return array($comment);
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on table rename
-     */
-    function getRenameTableExtraSQL ($xmldb_table, $newname) {
-
-        $results = array();
-
-        $newt = new XMLDBTable($newname);
-
-        $xmldb_field = new XMLDBField('id'); // Fields having sequences should be exclusively, id.
-
-        $oldseqname = $this->getTableName($xmldb_table) . '_' . $xmldb_field->getName() . '_seq';
-        $newseqname = $this->getTableName($newt) . '_' . $xmldb_field->getName() . '_seq';
-
-    /// Rename de sequence
-        $results[] = 'ALTER TABLE ' . $oldseqname . ' RENAME TO ' . $newseqname;
-
-    /// Rename all the check constraints in the table
-        $oldtablename = $this->getTableName($xmldb_table);
-        $newtablename = $this->getTableName($newt);
-
-        $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
-        $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
-
-        if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
-            foreach ($constraints as $constraint) {
-            /// Drop the old constraint
-                $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
-            /// Calculate the new constraint name
-                $newconstraintname = str_replace($oldconstraintprefix, $newconstraintprefix, $constraint->name);
-            /// Add the new constraint
-                $results[] = 'ALTER TABLE ' . $newtablename . ' ADD CONSTRAINT ' . $newconstraintname .
-                             ' CHECK ' . $constraint->description;
-             }
-         }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add the field to the table
-     * PostgreSQL is pretty standard but with one severe restriction under 7.4 that forces us to overload
-     * this function: Default clause is not allowed when adding fields.
-     * 
-     * This function can be safely removed once min req. for PG will be 8.0
-     */
-    function getAddFieldSQL($xmldb_table, $xmldb_field) {
-    
-        $results = array();
-
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-        $defaultvalue = null;
-
-    /// Save old flags
-        $old_skip_default = $this->alter_column_skip_default;
-        $old_skip_notnull = $this->alter_column_skip_notnull;
-
-    /// Prevent default clause and launch parent getAddField()
-        $this->alter_column_skip_default = true;
-        $this->alter_column_skip_notnull = true;
-        $results = parent::getAddFieldSQL($xmldb_table, $xmldb_field);
-
-    /// Re-set old flags
-        $this->alter_column_skip_default = $old_skip_default;
-        $this->alter_column_skip_notnull = $old_skip_notnull;
-
-    /// Add default (only if not skip_default)
-        if (!$this->alter_column_skip_default) {
-            if ($defaultclause = $this->getDefaultClause($xmldb_field)) {
-                $defaultvalue = $this->getDefaultValue($xmldb_field);
-                $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET' . $defaultclause; /// Add default clause
-            }
-        /// Update default value (if exists) to all the records
-            if ($defaultvalue !== null) {
-                $results[] = 'UPDATE ' . $tablename . ' SET ' . $fieldname . '=' . $defaultvalue;
-            }
-        }
-
-    /// Add not null (only if no skip_notnull)
-        if (!$this->alter_column_skip_notnull) {
-            if ($xmldb_field->getNotnull()) {
-                $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET NOT NULL'; /// Add not null
-            }
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table
-     * PostgreSQL has some severe limits:
-     *     - Any change of type or precision requires a new temporary column to be created, values to
-     *       be transfered potentially casting them, to apply defaults if the column is not null and 
-     *       finally, to rename it
-     *     - Changes in null/not null require the SET/DROP NOT NULL clause
-     *     - Changes in default require the SET/DROP DEFAULT clause
-     */
-    function getAlterFieldSQL($xmldb_table, $xmldb_field) {
-
-        global $db;
-
-        $results = array(); /// To store all the needed SQL commands
-
-    /// Get the quoted name of the table and field
-        $tablename = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
-
-    /// Take a look to field metadata
-        $meta = array_change_key_case($db->MetaColumns($tablename));
-        $metac = $meta[$fieldname];
-        $oldtype = strtolower($metac->type);
-        $oldmetatype = column_type($xmldb_table->getName(), $fieldname);
-        $oldlength = $metac->max_length;
-        $olddecimals = empty($metac->scale) ? null : $metac->scale;
-        $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
-        $olddefault = empty($metac->has_default) ? null : strtok($metac->default_value, ':');
-
-        $typechanged = true;  //By default, assume that the column type has changed
-        $precisionchanged = true;  //By default, assume that the column precision has changed
-        $decimalchanged = true;  //By default, assume that the column decimal has changed
-        $defaultchanged = true;  //By default, assume that the column default has changed
-        $notnullchanged = true;  //By default, assume that the column notnull has changed
-
-        $from_temp_fields = false; //By default don't assume we are going to use temporal fields
-
-    /// Detect if we are changing the type of the column
-        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && substr($oldmetatype, 0, 1) == 'I') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_NUMBER  && $oldmetatype == 'N') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_FLOAT   && $oldmetatype == 'F') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_CHAR    && substr($oldmetatype, 0, 1) == 'C') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && substr($oldmetatype, 0, 1) == 'X') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_BINARY  && $oldmetatype == 'B')) {
-            $typechanged = false;
-        }
-    /// Detect if we are changing the precision 
-        if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
-            ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
-            ($oldlength == -1) ||
-            ($xmldb_field->getLength() == $oldlength)) {
-            $precisionchanged = false;
-        }
-    /// Detect if we are changing the decimals
-        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) ||
-            ($xmldb_field->getType() == XMLDB_TYPE_CHAR) ||
-            ($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
-            ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
-            (!$xmldb_field->getDecimals()) ||
-            (!$olddecimals) ||
-            ($xmldb_field->getDecimals() == $olddecimals)) {
-            $decimalchanged = false;
-        }
-    /// Detect if we are changing the default
-        if (($xmldb_field->getDefault() === null && $olddefault === null) ||
-            ($xmldb_field->getDefault() === $olddefault) ||             //Check both equality and
-            ("'" . $xmldb_field->getDefault() . "'" === $olddefault)) {  //Equality with quotes because ADOdb returns the default with quotes
-            $defaultchanged = false;
-        }
-    /// Detect if we are changing the nullability
-        if (($xmldb_field->getNotnull() === $oldnotnull)) {
-            $notnullchanged = false;
-        }
-
-    /// TODO: Some combinations like
-    /// TODO: integer->integer
-    /// TODO: integer->text
-    /// TODO: number->text
-    /// TODO: text->text
-    /// TODO: do not require the use of temp columns, because PG 8.0 supports them automatically
-    /// TODO: with a simple "alter table zzz alter column yyy type new specs"
-    /// TODO: Must be implemented that way. Eloy 09/2007
-
-    /// If the type or the precision or the decimals have changed, then we need to:
-    ///     - create one temp column with the new specs
-    ///     - fill the new column with the values from the old one (casting if needed)
-    ///     - drop the old column
-    ///     - rename the temp column to the original name
-        if ($typechanged || $precisionchanged || $decimalchanged) {
-            $tempcolname = $xmldb_field->getName() . '_alter_column_tmp';
-        /// Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints
-            $this->alter_column_skip_notnull = true;
-            $this->alter_column_skip_default = true;
-            $xmldb_field->setName($tempcolname);
-        /// Create the temporal column
-            $results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field));
-        /// Detect some basic casting options
-            if ((substr($oldmetatype, 0, 1) == 'C' && $xmldb_field->getType() == XMLDB_TYPE_NUMBER) ||
-                (substr($oldmetatype, 0, 1) == 'C' && $xmldb_field->getType() == XMLDB_TYPE_FLOAT)) {
-                $copyorigin = 'CAST(CAST('.$fieldname.' AS TEXT) AS REAL)'; //From char to number or float
-            } else if ((substr($oldmetatype, 0, 1) == 'C' && $xmldb_field->getType() == XMLDB_TYPE_INTEGER)) {
-                $copyorigin = 'CAST(CAST('.$fieldname.' AS TEXT) AS INTEGER)'; //From char to integer
-            } else {
-                $copyorigin = $fieldname; //Direct copy between columns
-            }
-        /// Copy contents from original col to the temporal one
-            $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $copyorigin;
-        /// Drop the old column
-            $xmldb_field->setName($fieldname); //Set back the original field name
-            $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
-        /// Rename the temp column to the original one
-            $results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname;
-        /// Mark we have performed one change based in temp fields
-            $from_temp_fields = true;
-        }
-    /// If the default has changed or we have used one temp field
-        if ($defaultchanged || $from_temp_fields) {
-            if ($default_clause = $this->getDefaultClause($xmldb_field)) {
-                $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET' . $default_clause; /// Add default clause
-            } else {
-                if (!$from_temp_fields) { /// Only drop default if we haven't used the temp field, i.e. old column
-                    $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' DROP DEFAULT'; /// Drop default clause
-                }
-            }
-        }
-    /// If the not null has changed or we have used one temp field
-        if ($notnullchanged || $from_temp_fields) {
-            if ($xmldb_field->getNotnull()) {
-                $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET NOT NULL';
-            } else {
-                $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' DROP NOT NULL';
-            }
-        }
-
-    /// Return the results 
-        return $results;
-    }
-
-    /**
-     * Returns the code (array of statements) needed to execute extra statements on field rename
-     */
-    function getRenameFieldExtraSQL ($xmldb_table, $xmldb_field, $newname) {
-
-        $results = array();
-
-    /// If the field is enum, drop and re-create the check constraint
-        if ($xmldb_field->getEnum()) {
-        /// Drop the current enum
-            $results = array_merge($results, $this->getDropEnumSQL($xmldb_table, $xmldb_field));
-        /// Change field name (over a clone to avoid some potential problems later)
-            $new_xmldb_field = clone($xmldb_field);
-            $new_xmldb_field->setName($newname);
-        /// Recreate the enum
-            $results = array_merge($results, $this->getCreateEnumSQL($xmldb_table, $new_xmldb_field));
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum 
-     * (usually invoked from getModifyEnumSQL()
-     */
-    function getCreateEnumSQL($xmldb_table, $xmldb_field) {
-    /// All we have to do is to create the check constraint
-        return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
-                     ' ADD ' . $this->getEnumExtraSQL($xmldb_table, $xmldb_field));
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum 
-     * (usually invoked from getModifyEnumSQL()
-     */
-    function getDropEnumSQL($xmldb_table, $xmldb_field) {
-    /// Let's introspect to know the real name of the check constraint
-        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
-            $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
-            $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
-        /// All we have to do is to drop the check constraint
-            return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
-                     ' DROP CONSTRAINT ' . $constraint_name);
-        } else { /// Constraint not found. Nothing to do
-            return array();
-        }
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */
-    function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
-    /// Just a wrapper over the getAlterFieldSQL() function for PostgreSQL that
-    /// is capable of handling defaults
-        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */
-    function getDropDefaultSQL($xmldb_table, $xmldb_field) {
-    /// Just a wrapper over the getAlterFieldSQL() function for PostgreSQL that
-    /// is capable of handling defaults
-        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-    }
-
-    /**
-     * Given one XMLDBTable returns one array with all the check constrainsts
-     * in the table (fetched from DB)
-     * Optionally the function allows one xmldb_field to be specified in
-     * order to return only the check constraints belonging to one field.
-     * Each element contains the name of the constraint and its description
-     * If no check constraints are found, returns an empty array
-     */
-    function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
-
-        $results = array();
-
-        $tablename = $this->getTableName($xmldb_table);
-
-        if ($constraints = get_records_sql("SELECT co.conname AS name, co.consrc AS description
-                                              FROM pg_constraint co,
-                                                   pg_class cl
-                                             WHERE co.conrelid = cl.oid
-                                               AND co.contype = 'c'
-                                               AND cl.relname = '{$tablename}'")) {
-            foreach ($constraints as $constraint) {
-                $results[$constraint->name] = $constraint;
-            }
-        }
-
-    /// Filter by the required field if specified
-        if ($xmldb_field) {
-            $filtered_results = array();
-            $filter = $xmldb_field->getName();
-        /// Lets clean a bit each constraint description, looking for the filtered field
-            foreach ($results as $key => $result) {
-                $description = preg_replace('/\("(.*?)"\)/', '($1)', $result->description);// Double quotes out
-                $description = preg_replace('/[\(\)]/', '', $description);                 // Parenthesis out
-                $description = preg_replace('/::[a-z]+/i', '', $description);              // Casts out
-                $description = preg_replace("/({$filter})/i", '@$1@', $description);
-                $description = trim(preg_replace('/ or /i', ' OR ', $description));        // Uppercase or & trim
-            /// description starts by @$filter@ assume it's a constraint beloging to the field
-                if (preg_match("/^@{$filter}@/i", $description)) {
-                    $filtered_results[$key] = $result;
-                }
-            }
-        /// Assign filtered results to the final results array
-            $results =  $filtered_results;
-        }
-
-        return $results;
-    }
-
-/**
- * Given one XMLDBTable returns one string with the sequence of the table
- * in the table (fetched from DB)
- * The sequence name for Postgres has one standard name convention: 
- *     tablename_fieldname_seq
- * so we just calculate it and confirm it's present in pg_class
- * If no sequence is found, returns false
- */
-function getSequenceFromDB($xmldb_table) {
-
-    $tablename = $this->getTableName($xmldb_table);
-    $sequencename = $tablename . '_id_seq';
-
-    if (!get_record_sql("SELECT *
-                     FROM pg_class
-                     WHERE relname = '{$sequencename}'
-                       AND relkind = 'S'")) {
-        $sequencename = false;
-    }
-
-    return $sequencename;
-}
-
-    /**
-     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
-     * return if such name is currently in use (true) or no (false)
-     * (invoked from getNameForObject()
-     */
-    function isNameInUse($object_name, $type, $table_name) {
-        switch($type) {
-            case 'ix':
-            case 'uix':
-            case 'seq':
-                if ($check = get_records_sql("SELECT relname 
-                                              FROM pg_class 
-                                              WHERE lower(relname) = '" . strtolower($object_name) . "'")) {
-                    return true;
-                }
-                break;
-            case 'pk':
-            case 'uk':
-            case 'fk':
-            case 'ck':
-                if ($check = get_records_sql("SELECT conname 
-                                              FROM pg_constraint
-                                              WHERE lower(conname) = '" . strtolower($object_name) . "'")) {
-                    return true;
-                }
-                break;
-            case 'trg':
-                if ($check = get_records_sql("SELECT tgname 
-                                              FROM pg_trigger
-                                              WHERE lower(tgname) = '" . strtolower($object_name) . "'")) {
-                    return true;
-                }
-                break;
-        }
-        return false; //No name in use found
-    }
-
-    /**
-     * Returns an array of reserved words (lowercase) for this DB
-     */
-    function getReservedWords() {
-    /// This file contains the reserved words for PostgreSQL databases
-    /// http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
-        $reserved_words = array (
-            'all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc',
-            'asymmetric', 'authorization', 'between', 'binary', 'both', 'case',
-            'cast', 'check', 'collate', 'column', 'constraint', 'create', 'cross',
-            'current_date', 'current_role', 'current_time', 'current_timestamp',
-            'current_user', 'default', 'deferrable', 'desc', 'distinct', 'do',
-            'else', 'end', 'except', 'false', 'for', 'foreign', 'freeze', 'from',
-            'full', 'grant', 'group', 'having', 'ilike', 'in', 'initially', 'inner',
-            'intersect', 'into', 'is', 'isnull', 'join', 'leading', 'left', 'like',
-            'limit', 'localtime', 'localtimestamp', 'natural', 'new', 'not',
-            'notnull', 'null', 'off', 'offset', 'old', 'on', 'only', 'or', 'order',
-            'outer', 'overlaps', 'placing', 'primary', 'references', 'right', 'select',
-            'session_user', 'similar', 'some', 'symmetric', 'table', 'then', 'to',
-            'trailing', 'true', 'union', 'unique', 'user', 'using', 'verbose',
-            'when', 'where'
-        );
-        return $reserved_words;
-    }
-}
-
-?>
Index: auth/ldap/auth.php
===================================================================
RCS file: /cvsroot/moodle/moodle/auth/ldap/auth.php,v
retrieving revision 1.50
diff -u -r1.50 auth.php
--- auth/ldap/auth.php	25 Apr 2008 13:22:02 -0000	1.50
+++ auth/ldap/auth.php	15 May 2008 21:10:39 -0000
@@ -556,6 +556,8 @@
                 break;
         }
 
+/// TODO: remove these ugly hacks
+error('fix temporary table code in CAS');
 
         execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later
         echo "Creating temp table $temptable\n";
Index: search/indexlib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/search/indexlib.php,v
retrieving revision 1.11
diff -u -r1.11 indexlib.php
--- search/indexlib.php	2 May 2008 15:23:13 -0000	1.11
+++ search/indexlib.php	15 May 2008 21:11:30 -0000
@@ -37,7 +37,7 @@
             $time;        //date index was generated
     
     public function __construct($path = SEARCH_INDEX_PATH) {
-        global $CFG, $db;
+        global $CFG, $DB;
         
         $this->path = $path;
         
@@ -65,17 +65,17 @@
         $db_exists = false; //for now
         
         //get all the current tables in moodle
-        $admin_tables = $db->MetaTables();
+        $admin_tables = $DB->get_tables();
         
         //TODO: use new IndexDBControl class for database checks?
         
         //check if our search table exists
-        if (in_array($CFG->prefix.SEARCH_DATABASE_TABLE, $admin_tables)) {
+        if (in_array(SEARCH_DATABASE_TABLE, $admin_tables)) {
             //retrieve database information if it does
             $db_exists = true;
             
             //total documents
-            $this->dbcount = count_records(SEARCH_DATABASE_TABLE);
+            $this->dbcount = $DB->count_records(SEARCH_DATABASE_TABLE);
             
             //individual document types
             // $types = search_get_document_types();
@@ -83,7 +83,7 @@
             sort($types);
             
             foreach($types as $type) {
-                $c = count_records(SEARCH_DATABASE_TABLE, 'doctype', $type);
+                $c = $DB->count_records(SEARCH_DATABASE_TABLE, array('doctype'=>$type));
                 $this->types[$type] = (int)$c;
             }
         } else {
@@ -181,11 +181,11 @@
     * @uses CFG, db
     */
     public function checkTableExists() {
-        global $CFG, $db;
+        global $CFG, $DB;
         
         $table = SEARCH_DATABASE_TABLE;
-        $tables = $db->MetaTables();
-        if (in_array($CFG->prefix.$table, $tables)) {
+        $tables = $DB->get_tables();
+        if (in_array($table, $tables)) {
             return true;
         } 
         else {
Index: mod/hotpot/db/upgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/hotpot/db/upgrade.php,v
retrieving revision 1.3
diff -u -r1.3 upgrade.php
--- mod/hotpot/db/upgrade.php	1 May 2008 20:49:18 -0000	1.3
+++ mod/hotpot/db/upgrade.php	15 May 2008 21:11:29 -0000
@@ -4,7 +4,7 @@
 
 function xmldb_hotpot_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
 
     $result = true;
 
@@ -17,14 +17,13 @@
         require_once $CFG->dirroot.'/mod/hotpot/lib.php';
 
         // disable display of debugging messages
-        $db_debug_save = $db->debug;
-        $db->debug = false;
+        $DB->set_debug(false);
 
         notify('Processing hotpot grades, this may take a while if there are many hotpots...', 'notifysuccess');
         hotpot_update_grades();
 
-        // restore $db->debug
-        $db->debug = $db_debug_save;
+        // restore debug
+        $DB->set_debug(true);
     }
 
     return $result;
Index: mod/data/db/upgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/data/db/upgrade.php,v
retrieving revision 1.13
diff -u -r1.13 upgrade.php
--- mod/data/db/upgrade.php	1 May 2008 20:41:48 -0000	1.13
+++ mod/data/db/upgrade.php	15 May 2008 21:11:24 -0000
@@ -19,7 +19,9 @@
 
 function xmldb_data_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
+
+    $dbman = $DB->get_manager();
 
     $result = true;
 
@@ -32,8 +34,8 @@
         $field = new XMLDBField('asearchtemplate');
         $field->setAttributes(XMLDB_TYPE_TEXT, 'small', null, null, null, null, null, null, 'jstemplate');
 
-        if (!field_exists($table, $field)) {
-            $result = $result && add_field($table, $field);
+        if (!$dbman->field_exists($table, $field)) {
+            $result = $result && $dbman->add_field($table, $field);
         }
     }
 
@@ -41,14 +43,15 @@
         // Upgrade all the data->notification currently being
         // NULL to 0
         $sql = "UPDATE {$CFG->prefix}data SET notification=0 WHERE notification IS NULL";
-        $result = execute_sql($sql);
+        $result = $DB->execute($sql);
+
         $table = new XMLDBTable('data');
         $field = new XMLDBField('notification');
         // First step, Set NOT NULL
         $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'editany');
-        $result = $result && change_field_notnull($table, $field);
+        $result = $result && $dbman->change_field_notnull($table, $field);
         // Second step, Set default to 0
-        $result = $result && change_field_default($table, $field);
+        $result = $result && $dbman->change_field_default($table, $field);
     }
 
     return $result;
Index: mod/lesson/db/upgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/lesson/db/upgrade.php,v
retrieving revision 1.11
diff -u -r1.11 upgrade.php
--- mod/lesson/db/upgrade.php	1 May 2008 20:52:33 -0000	1.11
+++ mod/lesson/db/upgrade.php	15 May 2008 21:11:29 -0000
@@ -19,7 +19,9 @@
 
 function xmldb_lesson_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
+
+    $dbman = $DB->get_manager();
 
     $result = true;
 
@@ -32,11 +34,11 @@
         $field2 = new XMLDBField('usemaxgrade');
 
     /// Rename lesson->usegrademax to lesson->usemaxgrade. Some old sites can have it incorrect. MDL-13177
-        if (field_exists($table, $field) && !field_exists($table, $field2)) {
+        if ($dbman->field_exists($table, $field) && !$dbman->field_exists($table, $field2)) {
         /// Set field specs
             $field->setAttributes(XMLDB_TYPE_INTEGER, '3', null, XMLDB_NOTNULL, null, null, null, '0', 'ongoing');
         /// Launch rename field usegrademax to usemaxgrade
-            $result = $result && rename_field($table, $field, 'usemaxgrade');
+            $result = $result && $dbman->rename_field($table, $field, 'usemaxgrade');
         }
     }
 
Index: lib/xmldb/classes/generators/mssql_n/mssql_n.class.php
===================================================================
RCS file: lib/xmldb/classes/generators/mssql_n/mssql_n.class.php
diff -N lib/xmldb/classes/generators/mssql_n/mssql_n.class.php
--- lib/xmldb/classes/generators/mssql_n/mssql_n.class.php	10 Oct 2007 05:25:22 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,44 +0,0 @@
-<?php // $Id: mssql_n.class.php,v 1.3 2007/10/10 05:25:22 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class generate SQL code to be used against MSSQL
-/// with extended support to automatic handling of the "N"
-/// char for Unicode strings. As DB is the same, this inherits
-/// everything from XMLDBmssql
-
-require_once($CFG->libdir . '/xmldb/classes/generators/mssql/mssql.class.php');
-
-class XMLDBmssql_n extends XMLDBmssql {
-
-    /**
-     * Creates one new XMLDBmssql
-     */
-    function XMLDBmssql_n() {
-        XMLDBmssql::XMLDBmssql();
-    }
-}
-
-?>
Index: blog/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/blog/lib.php,v
retrieving revision 1.92
diff -u -r1.92 lib.php
--- blog/lib.php	30 Apr 2008 04:46:46 -0000	1.92
+++ blog/lib.php	15 May 2008 21:10:41 -0000
@@ -612,9 +612,7 @@
 
         $orderby = ' ORDER BY '. $sort .' ';
 
-        //global $db; $db->debug = true;
         $records = get_records_sql($SQL . $orderby, $limitfrom, $limitnum);
-        //$db->debug = false;
 
         if (empty($records)) {
             return array();
Index: lib/xmldb/classes/generators/mysql/mysql.class.php
===================================================================
RCS file: lib/xmldb/classes/generators/mysql/mysql.class.php
diff -N lib/xmldb/classes/generators/mysql/mysql.class.php
--- lib/xmldb/classes/generators/mysql/mysql.class.php	10 Oct 2007 05:25:24 -0000	1.38
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,386 +0,0 @@
-<?php // $Id: mysql.class.php,v 1.38 2007/10/10 05:25:24 nicolasconnault Exp $
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// NOTICE OF COPYRIGHT                                                   //
-//                                                                       //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//          http://moodle.com                                            //
-//                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
-//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
-//                                                                       //
-// This program is free software; you can redistribute it and/or modify  //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation; either version 2 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// This program is distributed in the hope that it will be useful,       //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details:                          //
-//                                                                       //
-//          http://www.gnu.org/copyleft/gpl.html                         //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/// This class generate SQL code to be used against MySQL
-/// It extends XMLDBgenerator so everything can be
-/// overriden as needed to generate correct SQL.
-
-class XMLDBmysql extends XMLDBGenerator {
-
-/// Only set values that are different from the defaults present in XMLDBgenerator
-
-    var $quote_string = '`';   // String used to quote names
-
-    var $default_for_char = '';      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
-
-    var $drop_default_clause_required = true; //To specify if the generator must use some DEFAULT clause to drop defaults
-    var $drop_default_clause = 'NULL'; //The DEFAULT clause required to drop defaults
-
-    var $primary_key_name = ''; //To force primary key names to one string (null=no force)
-
-    var $drop_primary_key = 'ALTER TABLE TABLENAME DROP PRIMARY KEY'; // Template to drop PKs
-                // with automatic replace for TABLENAME and KEYNAME
-
-    var $drop_unique_key = 'ALTER TABLE TABLENAME DROP KEY KEYNAME'; // Template to drop UKs
-                // with automatic replace for TABLENAME and KEYNAME
-
-    var $drop_foreign_key = 'ALTER TABLE TABLENAME DROP FOREIGN KEY KEYNAME'; // Template to drop FKs
-                // with automatic replace for TABLENAME and KEYNAME
-
-    var $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
-    var $sequence_name = 'auto_increment'; //Particular name for inline sequences in this generator
-
-    var $enum_extra_code = false; //Does the generator need to add extra code to generate code for the enums in the table
-
-    var $add_after_clause = true; // Does the generator need to add the after clause for fields
-
-    var $concat_character = null; //Characters to be used as concatenation operator. If not defined
-                                  //MySQL CONCAT function will be use
-
-    var $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY COLUMN COLUMNSPECS'; //The SQL template to alter columns
-
-    var $drop_index_sql = 'ALTER TABLE TABLENAME DROP INDEX INDEXNAME'; //SQL sentence to drop one index
-                                                               //TABLENAME, INDEXNAME are dinamically replaced
-
-    var $rename_index_sql = null; //SQL sentence to rename one index (MySQL doesn't support this!)
-                                      //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dinamically replaced
-
-    var $rename_key_sql = null; //SQL sentence to rename one key (MySQL doesn't support this!)
-                                      //TABLENAME, OLDKEYNAME, NEWKEYNAME are dinamically replaced
-
-    /**
-     * Creates one new XMLDBmysql
-     */
-    function XMLDBmysql() {
-        parent::XMLDBGenerator();
-        global $CFG;
-        $this->prefix = '';
-        $this->reserved_words = $this->getReservedWords();
-    }
-
-    /**
-     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
-     */
-    function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
-
-        switch ($xmldb_type) {
-            case XMLDB_TYPE_INTEGER:    // From http://mysql.com/doc/refman/5.0/en/numeric-types.html!
-                if (empty($xmldb_length)) {
-                    $xmldb_length = 10;
-                }
-                if ($xmldb_length > 9) {
-                    $dbtype = 'BIGINT';
-                } else if ($xmldb_length > 6) {
-                    $dbtype = 'INT';
-                } else if ($xmldb_length > 4) {
-                    $dbtype = 'MEDIUMINT';
-                } else if ($xmldb_length > 2) {
-                    $dbtype = 'SMALLINT';
-                } else {
-                    $dbtype = 'TINYINT';
-                }
-                $dbtype .= '(' . $xmldb_length . ')';
-                break;
-            case XMLDB_TYPE_NUMBER:
-                $dbtype = $this->number_type;
-                if (!empty($xmldb_length)) {
-                    $dbtype .= '(' . $xmldb_length;
-                    if (!empty($xmldb_decimals)) {
-                        $dbtype .= ',' . $xmldb_decimals;
-                    }
-                    $dbtype .= ')';
-                }
-                break;
-            case XMLDB_TYPE_FLOAT:
-                $dbtype = 'DOUBLE';
-                if (!empty($xmldb_decimals)) {
-                    if ($xmldb_decimals < 6) {
-                        $dbtype = 'FLOAT';
-                    }
-                }
-                if (!empty($xmldb_length)) {
-                    $dbtype .= '(' . $xmldb_length;
-                    if (!empty($xmldb_decimals)) {
-                        $dbtype .= ',' . $xmldb_decimals;
-                    }
-                    $dbtype .= ')';
-                }
-                break;
-            case XMLDB_TYPE_CHAR:
-                $dbtype = 'VARCHAR';
-                if (empty($xmldb_length)) {
-                    $xmldb_length='255';
-                }
-                $dbtype .= '(' . $xmldb_length . ')';
-                break;
-            case XMLDB_TYPE_TEXT:
-                if (empty($xmldb_length)) {
-                    $xmldb_length = 'small';
-                }
-                if ($xmldb_length == 'small') {
-                    $dbtype = 'TEXT';
-                } else if ($xmldb_length == 'medium') {
-                    $dbtype = 'MEDIUMTEXT';
-                } else {
-                    $dbtype = 'LONGTEXT';
-                }
-                break;
-            case XMLDB_TYPE_BINARY:
-                if (empty($xmldb_length)) {
-                    $xmldb_length = 'small';
-                }
-                if ($xmldb_length == 'small') {
-                    $dbtype = 'BLOB';
-                } else if ($xmldb_length == 'medium') {
-                    $dbtype = 'MEDIUMBLOB';
-                } else {
-                    $dbtype = 'LONGBLOB';
-                }
-                break;
-            case XMLDB_TYPE_DATETIME:
-                $dbtype = 'DATETIME';
-        }
-        return $dbtype;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum 
-     * (usually invoked from getModifyEnumSQL()
-     */
-    function getCreateEnumSQL($xmldb_table, $xmldb_field) {
-    /// For MySQL, just alter the field
-        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-    }
-
-    /**     
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum 
-     * (usually invoked from getModifyEnumSQL()
-     */
-    function getDropEnumSQL($xmldb_table, $xmldb_field) {
-    /// For MySQL, just alter the field
-        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */
-    function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
-    /// Just a wrapper over the getAlterFieldSQL() function for MySQL that
-    /// is capable of handling defaults
-        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-    }
-
-    /**
-     * Given one correct XMLDBField and the new name, returns the SQL statements
-     * to rename it (inside one array)
-     * MySQL is pretty diferent from the standard to justify this oveloading
-     */
-    function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
-
-        $results = array();  //Array where all the sentences will be stored
-
-    /// Need a clone of xmldb_field to perform the change leaving original unmodified
-        $xmldb_field_clone = clone($xmldb_field);
-
-    /// Change the name of the field to perform the change
-        $xmldb_field_clone->setName($xmldb_field_clone->getName() . ' ' . $newname);
-
-        $results[] = 'ALTER TABLE ' . $this->getTableName($xmldb_table) . ' CHANGE ' .
-                     $this->getFieldSQL($xmldb_field_clone);
-
-        return $results;
-    }
-
-    /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default 
-     * (usually invoked from getModifyDefaultSQL()
-     */
-    function getDropDefaultSQL($xmldb_table, $xmldb_field) {
-    /// Just a wrapper over the getAlterFieldSQL() function for MySQL that
-    /// is capable of handling defaults
-        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-    }
-
-    /**
-     * Given one XMLDB Field, return its enum SQL
-     */
-    function getEnumSQL ($xmldb_field) {
-        return 'enum(' . implode(', ', $xmldb_field->getEnumValues()) . ')';
-    }
-
-    /**
-     * Returns the code (in array) needed to add one comment to the table
-     */
-    function getCommentSQL ($xmldb_table) {
-
-        $comment = '';
-
-        if ($xmldb_table->getComment()) {
-            $comment .= 'ALTER TABLE ' . $this->getTableName($xmldb_table);
-            $comment .= " COMMENT='" . addslashes(substr($xmldb_table->getComment(), 0, 60)) . "'";
-        }
-        return array($comment);
-    }
-
-    /**
-     * Given one XMLDBTable returns one array with all the check constrainsts
-     * in the table (fetched from DB)
-     * Optionally the function allows one xmldb_field to be specified in
-     * order to return only the check constraints belonging to one field.
-     * Each element contains the name of the constraint and its description
-     * If no check constraints are found, returns an empty array
-     * MySQL doesn't have check constraints in this implementation, but
-     * we return them based on the enum fields in the table
-     */
-    function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
-
-        global $db;
-
-        $results = array();
-
-        $tablename = $this->getTableName($xmldb_table);
-
-    /// Fetch all the columns in the table
-        if ($columns = $db->MetaColumns($tablename)) {
-        /// Normalize array keys
-            $columns = array_change_key_case($columns, CASE_LOWER);
-        /// Iterate over columns searching for enums
-            foreach ($columns as $key => $column) {
-            /// Enum found, let's add it to the constraints list
-                if (!empty($column->enums)) {
-                    $result = new object;
-                    $result->name = $key;
-                    $result->description = implode(', ', $column->enums);
-                    $results[$key] = $result;
-                }
-            }
-        }
-
-    /// Filter by the required field if specified
-        if ($xmldb_field) {
-            $filter = $xmldb_field->getName();
-        /// Check if some of the checks belong to the field (easy under MySQL)
-            if (array_key_exists($filter, $results)) {
-                $results = array($filter => $results[$filter]);
-            } else {
-                $results = array();
-            }
-        }
-
-        return $results;
-    }
-
-    /**
-     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
-     * return if such name is currently in use (true) or no (false)
-     * (invoked from getNameForObject()
-     */
-    function isNameInUse($object_name, $type, $table_name) {
-
-        global $db;
-
-    /// Calculate the real table name
-        $xmldb_table = new XMLDBTable($table_name);
-        $tname = $this->getTableName($xmldb_table);
-        
-        switch($type) {
-            case 'ix':
-            case 'uix':
-            /// First of all, check table exists
-                $metatables = $db->MetaTables();
-                $metatables = array_flip($metatables);
-                $metatables = array_change_key_case($metatables, CASE_LOWER);
-                if (array_key_exists($tname,  $metatables)) {
-                /// Fetch all the indexes in the table
-                    if ($indexes = $db->MetaIndexes($tname)) {
-                    /// Normalize array keys
-                        $indexes = array_change_key_case($indexes, CASE_LOWER);
-                    /// Look for existing index in array
-                        if (array_key_exists(strtolower($object_name), $indexes)) {
-                            return true;
-                        }
-                    }
-                }
-                break;
-        }
-        return false; //No name in use found
-    }
-
-
-    /**
-     * Returns an array of reserved words (lowercase) for this DB
-     */
-    function getReservedWords() {
-    /// This file contains the reserved words for MySQL databases
-    /// from http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html
-        $reserved_words = array (
-            'add', 'all', 'alter', 'analyze', 'and', 'as', 'asc',
-            'asensitive', 'before', 'between', 'bigint', 'binary',
-            'blob', 'both', 'by', 'call', 'cascade', 'case', 'change',
-            'char', 'character', 'check', 'collate', 'column',
-            'condition', 'connection', 'constraint', 'continue',
-            'convert', 'create', 'cross', 'current_date', 'current_time',
-            'current_timestamp', 'current_user', 'cursor', 'database',
-            'databases', 'day_hour', 'day_microsecond',
-            'day_minute', 'day_second', 'dec', 'decimal', 'declare',
-            'default', 'delayed', 'delete', 'desc', 'describe',
-            'deterministic', 'distinct', 'distinctrow', 'div', 'double',
-            'drop', 'dual', 'each', 'else', 'elseif', 'enclosed', 'escaped',
-            'exists', 'exit', 'explain', 'false', 'fetch', 'float', 'float4',
-            'float8', 'for', 'force', 'foreign', 'from', 'fulltext', 'grant',
-            'group', 'having', 'high_priority', 'hour_microsecond',
-            'hour_minute', 'hour_second', 'if', 'ignore', 'in', 'index',
-            'infile', 'inner', 'inout', 'insensitive', 'insert', 'int', 'int1',
-            'int2', 'int3', 'int4', 'int8', 'integer', 'interval', 'into', 'is',
-            'iterate', 'join', 'key', 'keys', 'kill', 'leading', 'leave', 'left',
-            'like', 'limit', 'lines', 'load', 'localtime', 'localtimestamp',
-            'lock', 'long', 'longblob', 'longtext', 'loop', 'low_priority',
-            'match', 'mediumblob', 'mediumint', 'mediumtext',
-            'middleint', 'minute_microsecond', 'minute_second',
-            'mod', 'modifies', 'natural', 'not', 'no_write_to_binlog',
-            'null', 'numeric', 'on', 'optimize', 'option', 'optionally',
-            'or', 'order', 'out', 'outer', 'outfile', 'precision', 'primary',
-            'procedure', 'purge', 'raid0', 'read', 'reads', 'real',
-            'references', 'regexp', 'release', 'rename', 'repeat', 'replace',
-            'require', 'restrict', 'return', 'revoke', 'right', 'rlike', 'schema',
-            'schemas', 'second_microsecond', 'select', 'sensitive',
-            'separator', 'set', 'show', 'smallint', 'soname', 'spatial',
-            'specific', 'sql', 'sqlexception', 'sqlstate', 'sqlwarning',
-            'sql_big_result', 'sql_calc_found_rows', 'sql_small_result',
-            'ssl', 'starting', 'straight_join', 'table', 'terminated', 'then',
-            'tinyblob', 'tinyint', 'tinytext', 'to', 'trailing', 'trigger', 'true',
-            'undo', 'union', 'unique', 'unlock', 'unsigned', 'update',
-            'upgrade', 'usage', 'use', 'using', 'utc_date', 'utc_time',
-            'utc_timestamp', 'values', 'varbinary', 'varchar', 'varcharacter',
-            'varying', 'when', 'where', 'while', 'with', 'write', 'x509',
-            'xor', 'year_month', 'zerofill'
-        );
-        return $reserved_words;
-    }
-}
-
-?>
Index: enrol/authorize/db/upgrade.php
===================================================================
RCS file: /cvsroot/moodle/moodle/enrol/authorize/db/upgrade.php,v
retrieving revision 2.3
diff -u -r2.3 upgrade.php
--- enrol/authorize/db/upgrade.php	11 May 2008 18:40:39 -0000	2.3
+++ enrol/authorize/db/upgrade.php	15 May 2008 21:10:45 -0000
@@ -19,7 +19,7 @@
 
 function xmldb_enrol_authorize_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
 
     $result = true;
 
Index: grade/edit/outcome/import.php
===================================================================
RCS file: /cvsroot/moodle/moodle/grade/edit/outcome/import.php,v
retrieving revision 1.3
diff -u -r1.3 import.php
--- grade/edit/outcome/import.php	11 Feb 2008 02:22:48 -0000	1.3
+++ grade/edit/outcome/import.php	15 May 2008 21:10:46 -0000
@@ -175,7 +175,6 @@
         }
 
         //var_dump($csv_data);
-        //$db->debug = 3498723498237; // .. very large randomly-typed random value
 
         if ($local_scope) {
             $outcome = get_records_select('grade_outcomes', 'shortname = "'. $csv_data[$imported_headers['outcome_shortname']] .'" and courseid = '. $courseid );
Index: admin/xmldb/actions/check_bigints/check_bigints.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/check_bigints/check_bigints.class.php,v
retrieving revision 1.3
diff -u -r1.3 check_bigints.class.php
--- admin/xmldb/actions/check_bigints/check_bigints.class.php	10 Oct 2007 05:25:27 -0000	1.3
+++ admin/xmldb/actions/check_bigints/check_bigints.class.php	15 May 2008 21:10:30 -0000
@@ -76,7 +76,10 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB, $db;
+        global $CFG, $XMLDB, $db, $DB;
+
+        $dbman = $DB->get_manager();
+        $dbfamily = $DB->get_dbfamily();
 
     /// And we nedd some ddl suff
         require_once ($CFG->libdir . '/ddllib.php');
@@ -85,7 +88,7 @@
         $wrong_fields = array();
 
     /// Correct fields must be type bigint for MySQL and int8 for PostgreSQL
-        switch ($CFG->dbfamily) {
+        switch ($dbfamily) {
             case 'mysql':
                 $correct_type = 'bigint';
                 break;
@@ -106,7 +109,7 @@
             $o = '<table class="generalbox" border="0" cellpadding="5" cellspacing="0" id="notice">';
             $o.= '  <tr><td class="generalboxcontent">';
             $o.= '    <p class="centerpara">' . $this->str['confirmcheckbigints'] . '</p>';
-            if ($CFG->dbfamily == 'mysql') {
+            if ($dbfamily == 'mysql') {
                 $o.= '    <p class="centerpara">' . $this->str['mysqlextracheckbigints'] . '</p>';
             }
             $o.= '    <table class="boxaligncenter" cellpadding="20"><tr><td>';
@@ -140,10 +143,6 @@
                     }
                 /// Load the XML file
                     $xmldb_file = new XMLDBFile($dbdir->path . '/install.xml');
-                /// Load the needed XMLDB generator
-                    $classname = 'XMLDB' . $CFG->dbtype;
-                    $generator = new $classname();
-                    $generator->setPrefix($CFG->prefix);
 
                 /// Only if the file exists
                     if (!$xmldb_file->fileExists()) {
@@ -164,13 +163,11 @@
                     /// Foreach table, process its fields
                         foreach ($xmldb_tables as $xmldb_table) {
                         /// Skip table if not exists
-                            if (!table_exists($xmldb_table)) {
+                            if (!$dbman->table_exists($xmldb_table)) {
                                 continue;
                             }
                         /// Fetch metadata from phisical DB. All the columns info.
-                            if ($metacolumns = $db->MetaColumns($CFG->prefix . $xmldb_table->getName())) {
-                                $metacolumns = array_change_key_case($metacolumns, CASE_LOWER);
-                            } else {
+                            if (!$metacolumns = $DB->get_columns($xmldb_table->getName())) {
                             //// Skip table if no metacolumns is available for it
                                 continue;
                             }
@@ -193,7 +190,7 @@
                                 /// Going to check this field in DB
                                     $o.='            <li>' . $this->str['field'] . ': ' . $xmldb_field->getName() . ' ';
                                 /// Detect if the phisical field is wrong and, under mysql, check for incorrect signed fields too
-                                    if ($metacolumn->type != $correct_type || ($CFG->dbfamily == 'mysql' && $xmldb_field->getUnsigned() && !$metacolumn->unsigned)) {
+                                    if ($metacolumn->type != $correct_type || ($dbfamily == 'mysql' && $xmldb_field->getUnsigned() && !$metacolumn->unsigned)) {
                                         $o.='<font color="red">' . $this->str['wrong'] . '</font>';
                                     /// Add the wrong field to the list
                                         $obj = new object;
@@ -233,18 +230,22 @@
                     $xmldb_table = $obj->table;
                     $xmldb_field = $obj->field;
                 /// MySQL directly supports this
-                    if ($CFG->dbfamily == 'mysql') {
-                        $sqlarr = $xmldb_table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $xmldb_field, true);
+
+// TODO: move this hack to generators!!
+
+                    if ($dbfamily == 'mysql') {
+                        $sqlarr = $dbman->generator->getAlterFieldSQL($xmldb_table, $xmldb_field);
                 /// PostgreSQL (XMLDB implementation) is a bit, er... imperfect.
-                    } else if ($CFG->dbfamily == 'postgres') {
-                        $sqlarr = array('ALTER TABLE ' . $CFG->prefix . $xmldb_table->getName() .
+                    } else if ($dbfamily == 'postgres') {
+                        $sqlarr = array('ALTER TABLE ' . $DB->get_prefix() . $xmldb_table->getName() .
                                   ' ALTER COLUMN ' . $xmldb_field->getName() . ' TYPE BIGINT;');
                     }
                     $r.= '            <li>' . $this->str['table'] . ': ' . $xmldb_table->getName() . '. ' .
                                               $this->str['field'] . ': ' . $xmldb_field->getName() . '</li>';
                 /// Add to output if we have sentences
                     if ($sqlarr) {
-                        $s.= '<code>' . str_replace("\n", '<br />', implode('<br />', $sqlarr)) . '</code><br />';
+                        $sqlarr = $dbman->generator->getEndedStatements($sqlarr);
+                        $s.= '<code>' . str_replace("\n", implode('<br />', $sqlarr)). '</code><br />';
                     }
                 }
                 $r.= '        </ul>';
Index: mod/data/import.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/data/import.php,v
retrieving revision 1.27
diff -u -r1.27 import.php
--- mod/data/import.php	14 May 2008 18:11:22 -0000	1.27
+++ mod/data/import.php	15 May 2008 21:11:24 -0000
@@ -104,7 +104,6 @@
         if (!$records = data_get_records_csv($filename, $fielddelimiter, $fieldenclosure)) {
             print_error('get_records_csv failed to read data from the uploaded file. Please check file for field name typos and formatting errors.');
         } else {
-            //$db->debug = true;
             $fieldnames = array_shift($records);
 
             foreach ($records as $record) {
Index: admin/xmldb/actions/test/test.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/test/test.class.php,v
retrieving revision 1.39
diff -u -r1.39 test.class.php
--- admin/xmldb/actions/test/test.class.php	10 Oct 2007 05:25:18 -0000	1.39
+++ admin/xmldb/actions/test/test.class.php	15 May 2008 21:10:34 -0000
@@ -58,10 +58,10 @@
         $this->does_generate = ACTION_GENERATE_HTML;
 
     /// These are always here
-        global $CFG, $XMLDB, $db;
-
-    /// ADD YOUR CODE HERE
-        require_once ($CFG->libdir . '/ddllib.php');
+        global $XMLDB, $DB, $CFG;
+        $dbman = $DB->get_manager();
+        $gen = $dbman->generator;
+        $dbfamily = $DB->get_dbfamily();
 
     /// Where all the tests will be stored
         $tests = array();
@@ -74,16 +74,16 @@
 
     /// Silenty drop any previous test tables
         $table = new XMLDBTable('testtable');
-        if (table_exists($table)) {
-            $status = drop_table($table, true, false);
+        if ($dbman->table_exists($table)) {
+            $status = $dbman->drop_table($table, true, false);
         }
         $table = new XMLDBTable ('anothertest');
-        if (table_exists($table)) {
-            $status = drop_table($table, true, false);
+        if ($dbman->table_exists($table)) {
+            $status = $dbman->drop_table($table, true, false);
         }
         $table = new XMLDBTable ('newnameforthetable');
-        if (table_exists($table)) {
-            $status = drop_table($table, true, false);
+        if ($dbman->table_exists($table)) {
+            $status = $dbman->drop_table($table, true, false);
         }
 
     /// 1st test. Complete table creation.
@@ -118,10 +118,10 @@
 
     /// Get SQL code and execute it
         $test = new stdClass;
-        $test->sql = $table->getCreateTableSQL($CFG->dbtype, $CFG->prefix, true);
-        $test->status = create_table($table, false, false);
+        $test->sql = $gen->getCreateTableSQL($table);
+        $test->status = $dbman->create_table($table, false, false);
         if (!$test->status) {
-            $test->error = $db->ErrorMsg();
+            $test->error = $DB->get_last_error();
         }
         $tests['create table'] = $test;
 
@@ -129,10 +129,10 @@
         if ($test->status) {
         /// Get SQL code and execute it
             $test = new stdClass;
-            $test->sql = $table->getDropTableSQL($CFG->dbtype, $CFG->prefix, true);
-            $test->status = drop_table($table, false, false);
+            $test->sql = $gen->getDropTableSQL($table);
+            $test->status = $dbman->drop_table($table, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop table'] = $test;
         }
@@ -150,10 +150,10 @@
             $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
         /// Get SQL code and execute it
             $test = new stdClass;
-            $test->sql = $table->getCreateTableSQL($CFG->dbtype, $CFG->prefix, true);
-            $test->status = create_table($table, false, false);
+            $test->sql = $gen->getCreateTableSQL($table);
+            $test->status = $dbman->create_table($table, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['create table - 2'] = $test;
         }
@@ -164,13 +164,13 @@
         $rec->secondname = 'Dougiamas';
         $rec->intro = 'The creator of Moodle';
         $rec->grade = 10.0001;
-        insert_record('anothertest', $rec);
+        $DB->insert_record('anothertest', $rec);
         $rec->course = 2;
         $rec->name = 'Eloy';
         $rec->secondname = 'Lafuente';
         $rec->intro = 'One poor developer';
         $rec->grade = 9.99;
-        insert_record('anothertest', $rec);
+        $DB->insert_record('anothertest', $rec);
 
     /// 4th test. Adding one complex enum field
         if ($test->status) {
@@ -179,10 +179,10 @@
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
         /// Get SQL code and execute it
             $test = new stdClass;
-            $test->sql = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = add_field($table, $field, false, false);
+            $test->sql = $gen->getAddFieldSQL($table, $field);
+            $test->status = $dbman->add_field($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add enum field'] = $test;
         }
@@ -191,10 +191,10 @@
         if ($test->status) {
         /// Create a new field with complex specs (enums are good candidates)
             $test = new stdClass;
-            $test->sql = $table->getDropFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = drop_field($table, $field, false, false);
+            $test->sql = $gen->getDropFieldSQL($table, $field);
+            $test->status = $dbman->drop_field($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop enum field'] = $test;
         }
@@ -206,10 +206,10 @@
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
         /// Get SQL code and execute it
             $test = new stdClass;
-            $test->sql = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = add_field($table, $field, false, false);
+            $test->sql = $gen->getAddFieldSQL($table, $field);
+            $test->status = $dbman->add_field($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add enum field again'] = $test;
         }
@@ -221,10 +221,10 @@
             $field->setAttributes(XMLDB_TYPE_INTEGER, '6', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 0, 'type');
         /// Get SQL code and execute it
             $test = new stdClass;
-            $test->sql = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = add_field($table, $field, false, false);
+            $test->sql = $gen->getAddFieldSQL($table, $field);
+            $test->status = $dbman->add_field($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add numeric field'] = $test;
         }
@@ -234,10 +234,10 @@
         /// Create a new field with complex specs (enums are good candidates)
             $field = new XMLDBField('type');
             $test = new stdClass;
-            $test->sql = $table->getDropFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = drop_field($table, $field, false, false);
+            $test->sql = $gen->getDropFieldSQL($table, $field);
+            $test->status = $dbman->drop_field($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop enum field again'] = $test;
         }
@@ -249,10 +249,10 @@
             $field = new XMLDBField('course');
             $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, '0');
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_type($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_type($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field type (int2char)'] = $test;
         }
@@ -264,10 +264,10 @@
             $field = new XMLDBField('course');
             $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_type($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_type($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field type (char2int)'] = $test;
         }
@@ -279,10 +279,10 @@
             $field = new XMLDBField('grade');
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, "test'n drop");
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_type($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_type($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field type (number2char)'] = $test;
         }
@@ -294,10 +294,10 @@
             $field = new XMLDBField('grade');
             $field->setAttributes(XMLDB_TYPE_FLOAT, '20,10', XMLDB_UNSIGNED, null, null, null, null, null);
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_type($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_type($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field type (char2float)'] = $test;
         }
@@ -309,10 +309,10 @@
             $field = new XMLDBField('grade');
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'test');
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_type($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_type($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field type (float2char)'] = $test;
         }
@@ -324,10 +324,10 @@
             $field = new XMLDBField('grade');
             $field->setAttributes(XMLDB_TYPE_NUMBER, '20,10', XMLDB_UNSIGNED, null, null, null, null, null);
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_type($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_type($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field type (char2number)'] = $test;
         }
@@ -340,10 +340,10 @@
             $field = new XMLDBField('intro');
             $field->setAttributes(XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null, null, null);
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_precision($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_precision($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field precision (text)'] = $test;
         }
@@ -355,10 +355,10 @@
             $field = new XMLDBField('secondname');
             $field->setAttributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, null);
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_precision($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_precision($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field precision (char)'] = $test;
         }
@@ -370,10 +370,10 @@
             $field = new XMLDBField('grade');
             $field->setAttributes(XMLDB_TYPE_NUMBER, '10,2', null, null, null, null, null, null);
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_precision($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_precision($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field precision (number)'] = $test;
         }
@@ -385,10 +385,10 @@
             $field = new XMLDBField('course');
             $field->setAttributes(XMLDB_TYPE_INTEGER, '5', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_precision($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_precision($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field precision (integer) to smaller one'] = $test;
         }
@@ -400,10 +400,10 @@
             $field = new XMLDBField('grade');
             $field->setAttributes(XMLDB_TYPE_NUMBER, '10,2', XMLDB_UNSIGNED, null, null, null, null, null);
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_unsigned($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_unsigned($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field sign (unsigned)'] = $test;
         }
@@ -415,10 +415,10 @@
             $field = new XMLDBField('grade');
             $field->setAttributes(XMLDB_TYPE_NUMBER, '10,2', null, null, null, null, null, null);
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_unsigned($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_unsigned($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field sign (signed)'] = $test;
         }
@@ -430,10 +430,10 @@
             $field = new XMLDBField('name');
             $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, 'Moodle');
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_notnull($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_notnull($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field nullability (not null)'] = $test;
         }
@@ -445,10 +445,10 @@
             $field = new XMLDBField('name');
             $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle');
 
-            $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_notnull($table, $field, false, false);
+            $test->sql = $gen->getAlterFieldSQL($table, $field);
+            $test->status = $dbman->change_field_notnull($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['change field nullability (null)'] = $test;
         }
@@ -460,10 +460,10 @@
             $field = new XMLDBField('name');
             $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, null);
 
-            $test->sql = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_default($table, $field, false, false);
+            $test->sql = $gen->getModifyDefaultSQL($table, $field);
+            $test->status = $dbman->change_field_default($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop field default of NULL field'] = $test;
         }
@@ -475,10 +475,10 @@
             $field = new XMLDBField('name');
             $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle');
 
-            $test->sql = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_default($table, $field, false, false);
+            $test->sql = $gen->getModifyDefaultSQL($table, $field);
+            $test->status = $dbman->change_field_default($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add field default of NULL field'] = $test;
         }
@@ -490,10 +490,10 @@
             $field = new XMLDBField('secondname');
             $field->setAttributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, 'Moodle2');
 
-            $test->sql = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_default($table, $field, false, false);
+            $test->sql = $gen->getModifyDefaultSQL($table, $field);
+            $test->status = $dbman->change_field_default($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add field default of NOT NULL field'] = $test;
         }
@@ -506,10 +506,10 @@
             $field = new XMLDBField('secondname');
             $field->setAttributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, null);
 
-            $test->sql = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_default($table, $field, false, false);
+            $test->sql = $gen->getModifyDefaultSQL($table, $field);
+            $test->status = $dbman->change_field_default($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop field default of NOT NULL field'] = $test;
         }
@@ -521,10 +521,10 @@
             $index = new XMLDBIndex('secondname');
             $index->setAttributes(XMLDB_INDEX_UNIQUE, array('name', 'secondname', 'grade'));
 
-            $test->sql = $table->getAddIndexSQL($CFG->dbtype, $CFG->prefix, $index, true);
-            $test->status = add_index($table, $index, false, false);
+            $test->sql = $gen->getAddIndexSQL($table, $index);
+            $test->status = $dbman->add_index($table, $index, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add unique index'] = $test;
         }
@@ -536,10 +536,10 @@
             $index = new XMLDBIndex('secondname');
             $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('course', 'name'));
 
-            $test->sql = $table->getAddIndexSQL($CFG->dbtype, $CFG->prefix, $index, true);
-            $test->status = add_index($table, $index, false, false);
+            $test->sql = $gen->getAddIndexSQL($table, $index);
+            $test->status = $dbman->add_index($table, $index, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add not unique index'] = $test;
         }
@@ -551,7 +551,7 @@
             $index = new XMLDBIndex('secondname');
             $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('name', 'course'));
 
-            if ($indexfound = find_index_name($table, $index)) {
+            if ($indexfound = $dbman->find_index_name($table, $index)) {
                 $test->status = true;
                 $test->sql = array();
             } else {
@@ -570,10 +570,10 @@
             $index = new XMLDBIndex('name');
             $index->setAttributes(XMLDB_INDEX_UNIQUE, array('name', 'grade', 'secondname'));
 
-            $test->sql = $table->getDropIndexSQL($CFG->dbtype, $CFG->prefix, $index, true);
-            $test->status = drop_index($table, $index, false, false);
+            $test->sql = $gen->getDropIndexSQL($table, $index);
+            $test->status = $dbman->drop_index($table, $index, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop index'] = $test;
         }
@@ -585,10 +585,10 @@
             $key = new XMLDBKey('id-course-grade');
             $key->setAttributes(XMLDB_KEY_UNIQUE, array('id', 'course', 'grade'));
 
-            $test->sql = $table->getAddKeySQL($CFG->dbtype, $CFG->prefix, $key, true);
-            $test->status = add_key($table, $key, false, false);
+            $test->sql = $gen->getAddKeySQL($table, $key);
+            $test->status = $dbman->add_key($table, $key, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add unique key'] = $test;
         }
@@ -600,10 +600,10 @@
             $key = new XMLDBKey('course');
             $key->setAttributes(XMLDB_KEY_FOREIGN_UNIQUE, array('course'), 'anothertest', array('id'));
 
-            $test->sql = $table->getAddKeySQL($CFG->dbtype, $CFG->prefix, $key, true);
-            $test->status = add_key($table, $key, false, false);
+            $test->sql = $gen->getAddKeySQL($table, $key);
+            $test->status = $dbman->add_key($table, $key, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add foreign+unique key'] = $test;
         }
@@ -615,10 +615,10 @@
             $key = new XMLDBKey('course');
             $key->setAttributes(XMLDB_KEY_FOREIGN_UNIQUE, array('course'), 'anothertest', array('id'));
 
-            $test->sql = $table->getDropKeySQL($CFG->dbtype, $CFG->prefix, $key, true);
-            $test->status = drop_key($table, $key, false, false);
+            $test->sql = $gen->getDropKeySQL($table, $key);
+            $test->status = $dbman->drop_key($table, $key, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop foreign+unique key'] = $test;
         }
@@ -630,10 +630,10 @@
             $key = new XMLDBKey('course');
             $key->setAttributes(XMLDB_KEY_FOREIGN, array('course'), 'anothertest', array('id'));
 
-            $test->sql = $table->getAddKeySQL($CFG->dbtype, $CFG->prefix, $key, true);
-            $test->status = add_key($table, $key, false, false);
+            $test->sql = $gen->getAddKeySQL($table, $key);
+            $test->status = $dbman->add_key($table, $key, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add foreign key'] = $test;
         }
@@ -645,10 +645,10 @@
             $key = new XMLDBKey('course');
             $key->setAttributes(XMLDB_KEY_FOREIGN, array('course'), 'anothertest', array('id'));
 
-            $test->sql = $table->getDropKeySQL($CFG->dbtype, $CFG->prefix, $key, true);
-            $test->status = drop_key($table, $key, false, false);
+            $test->sql = $gen->getDropKeySQL($table, $key);
+            $test->status = $dbman->drop_key($table, $key, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop foreign key'] = $test;
         }
@@ -660,11 +660,12 @@
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
         /// Get SQL code and execute it
             $test = new stdClass;
-            $test->sql = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = add_field($table, $field, false, false);
+            $test->sql = $gen->getAddFieldSQL($table, $field);
+            $test->status = $dbman->add_field($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
+
             $tests['add field with enum'] = $test;
         }
 
@@ -674,11 +675,10 @@
             $test = new stdClass;
             $field = new XMLDBField('type');
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'general', 'course');
-
-            $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_enum($table, $field, false, false);
+            $test->sql = $gen->getModifyEnumSQL($table, $field);
+            $test->status = $dbman->change_field_enum($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['delete enumlist from one field'] = $test;
         }
@@ -689,10 +689,10 @@
             $test = new stdClass;
             $field = new XMLDBField('type');
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
-            $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_enum($table, $field, false, false);
+            $test->sql = $gen->getModifyEnumSQL($table, $field);
+            $test->status = $dbman->change_field_enum($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add enumlist to one field'] = $test;
         }
@@ -703,13 +703,14 @@
             $test = new stdClass;
             $index = new XMLDBIndex('anyname');
             $index->setAttributes(XMLDB_INDEX_UNIQUE, array('name', 'course'));
-
-            $test->sql = $table->getRenameIndexSQL($CFG->dbtype, $CFG->prefix, $index, 'newnamefortheindex', true);
-            $test->status = rename_index($table, $index, 'newnamefortheindex', false, false);
+            $test->sql = $gen->getRenameIndexSQL($table, $index, 'newnamefortheindex');
+            $test->status = $dbman->rename_index($table, $index, 'newnamefortheindex', false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['rename index (experimental. DO NOT USE IT)'] = $test;
+            $test = new stdClass;
+            $test->status = true; // ignore errors here
         }
 
     /// 40th test. Renaming one key
@@ -719,12 +720,19 @@
             $key = new XMLDBKey('anyname');
             $key->setAttributes(XMLDB_KEY_UNIQUE, array('id', 'course', 'grade'));
 
-            $test->sql = $table->getRenameKeySQL($CFG->dbtype, $CFG->prefix, $key, 'newnameforthekey', true);
-            $test->status = rename_key($table, $key, 'newnameforthekey', false, false);
+            $test->sql = $gen->getRenameKeySQL($table, $key, 'newnameforthekey', true);
+            $olddebug = $CFG->debug;
+            if ($olddebug > DEBUG_ALL) {
+                $CFG->debug = DEBUG_ALL; // do not show experimental debug warning
+            }
+            $test->status = $dbman->rename_key($table, $key, 'newnameforthekey', false, false);
+            $CFG->debug = $olddebug;
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['rename key (experimental. DO NOT USE IT)'] = $test;
+            $test = new stdClass;
+            $test->status = true; // ignore errors here
         }
 
     /// 41th test. Renaming one field
@@ -734,10 +742,10 @@
             $field = new XMLDBField('type');
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
 
-            $test->sql = $table->getRenameFieldSQL($CFG->dbtype, $CFG->prefix, $field, 'newnameforthefield', true);
-            $test->status = rename_field($table, $field, 'newnameforthefield', false, false);
+            $test->sql = $gen->getRenameFieldSQL($table, $field, 'newnameforthefield', true);
+            $test->status = $dbman->rename_field($table, $field, 'newnameforthefield', false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['rename field'] = $test;
         }
@@ -747,10 +755,10 @@
         /// Get SQL code and execute it
             $test = new stdClass;
 
-            $test->sql = $table->getRenameTableSQL($CFG->dbtype, $CFG->prefix, 'newnameforthetable', true);
-            $test->status = rename_table($table, 'newnameforthetable', false, false);
+            $test->sql = $gen->getRenameTableSQL($table, 'newnameforthetable', true);
+            $test->status = $dbman->rename_table($table, 'newnameforthetable', false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['rename table'] = $test;
         }
@@ -763,16 +771,16 @@
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course');
         /// Get SQL code and execute it
             $test = new stdClass;
-            $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_enum($table, $field, false, false);
+            $test->sql = $gen->getModifyEnumSQL($table, $field);
+            $test->status = $dbman->change_field_enum($table, $field, false, false);
         /// Let's see if the constraint exists to alter results
-            if (check_constraint_exists($table, $field)) {
+            if ($dbman->check_constraint_exists($table, $field)) {
                 $test->sql = array('Nothing executed. Enum already exists. Correct.');
             } else {
                 $test->status = false;
             }
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['add enum to field containing enum'] = $test;
         }
@@ -785,10 +793,10 @@
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'general', 'course');
         /// Get SQL code and execute it
             $test = new stdClass;
-            $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_enum($table, $field, false, false);
+            $test->sql = $gen->getModifyEnumSQL($table, $field);
+            $test->status = $dbman->change_field_enum($table, $field, false, false);
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop enum from field containing enum'] = $test;
         }
@@ -801,16 +809,16 @@
             $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'general', 'course');
         /// Get SQL code and execute it
             $test = new stdClass;
-            $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true);
-            $test->status = change_field_enum($table, $field, false, false);
+            $test->sql = $gen->getModifyEnumSQL($table, $field);
+            $test->status = $dbman->change_field_enum($table, $field, false, false);
         /// Let's see if the constraint exists to alter results
-            if (!check_constraint_exists($table, $field)) {
+            if (!$dbman->check_constraint_exists($table, $field)) {
                 $test->sql = array('Nothing executed. Enum does not exists. Correct.');
             } else {
                 $test->status = false;
             }
             if (!$test->status) {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['drop enum from field not containing enum'] = $test;
         }
@@ -818,10 +826,10 @@
     /// 46th test. Getting the PK sequence name for one table
         if ($test->status) {
             $test = new stdClass;
-            $test->sql =  array(find_sequence_name($table));
-            $test->status = find_sequence_name($table);
+            $test->sql =  array($dbman->find_sequence_name($table));
+            $test->status = $dbman->find_sequence_name($table);
             if (!$test->status) {
-                if (!$test->error = $db->ErrorMsg()) { //If no db errors, result is ok. Just the driver doesn't support this
+                if (!$test->error = $DB->get_last_error()) { //If no db errors, result is ok. Just the driver doesn't support this
                     $test->sql = array('Not needed for this DB. Correct.');
                     $test->status = true;
                 }
@@ -843,30 +851,29 @@
             }
 
         /// Build the record to insert
-            $rec->intro = addslashes($fulltext);
+            $rec->intro = $fulltext;
             $rec->name = 'texttest';
         /// Calculate its length
             $textlen = $textlib->strlen($fulltext);
-            if ($rec->id = insert_record('newnameforthetable', $rec)) {
-                if ($new = get_record('newnameforthetable', 'id', $rec->id)) {
-                    delete_records('newnameforthetable', 'id', $new->id);
+            if ($rec->id = $DB->insert_record('newnameforthetable', $rec)) {
+                if ($new = $DB->get_record('newnameforthetable', array('id'=>$rec->id))) {
+                    $DB->delete_records('newnameforthetable', array('id'=>$new->id));
                     $newtextlen = $textlib->strlen($new->intro);
                     if ($fulltext === $new->intro) {
                         $test->sql = array($newtextlen . ' cc. (text) sent and received ok');
                         $test->status = true;
                     } else {
-                        $test->error = $db->ErrorMsg();
+                        $test->error = $DB->get_last_error();
                         $test->sql = array($newtextlen . ' cc. (text) transfer failed. Data changed!');
                         print_object($new);
                         $test->status = false;
                     }
                 } else {
-                    $test->error = $db->ErrorMsg();
+                    $test->error = $DB->get_last_error().'xx';
                 }
             } else {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error().'yy'.var_export($rec->id, true);
             }
-            $tests['insert record '. $textlen . ' cc. (text)'] = $test;
         }
 
     /// 48th test. Inserting BINARY contents
@@ -874,26 +881,26 @@
             $test = new stdClass;
             $test->status = false;
         /// Build the record to insert
-            $rec->avatar = addslashes($fulltext);
+            $rec->avatar = $fulltext;
             $rec->name = 'binarytest';
         /// Calculate its length
             $textlen = strlen($fulltext);
-            if ($rec->id = insert_record('newnameforthetable', $rec)) {
-                if ($new = get_record('newnameforthetable', 'id', $rec->id)) {
+            if ($rec->id = $DB->insert_record('newnameforthetable', $rec)) {
+                if ($new = $DB->get_record('newnameforthetable', array('id'=>$rec->id))) {
                     $newtextlen = strlen($new->avatar);
                     if ($fulltext === $new->avatar) {
                         $test->sql = array($newtextlen . ' bytes (binary) sent and received ok');
                         $test->status = true;
                     } else {
-                        $test->error = $db->ErrorMsg();
+                        $test->error = $DB->get_last_error();
                         $test->sql = array($newtextlen . ' bytes (binary) transfer failed. Data changed!');
                         $test->status = false;
                     }
                 } else {
-                    $test->error = $db->ErrorMsg();
+                    $test->error = $DB->get_last_error();
                 }
             } else {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['insert record '. $textlen . ' bytes (binary)'] = $test;
         }
@@ -904,14 +911,14 @@
             $test->status = false;
             $test->sql = array();
         /// Build the record to insert
-            $rec->intro = addslashes($basetext);
-            $rec->avatar = addslashes($basetext);
+            $rec->intro = $basetext;
+            $rec->avatar = $basetext;
             $rec->name = 'updatelobs';
         /// Calculate its length
             $textlen = $textlib->strlen($basetext);
             $imglen = strlen($basetext);
-            if (update_record('newnameforthetable', $rec)) {
-                if ($new = get_record('newnameforthetable', 'id', $rec->id)) {
+            if ($DB->update_record('newnameforthetable', $rec)) {
+                if ($new = $DB->get_record('newnameforthetable', array('id'=>$rec->id))) {
                     $newtextlen = $textlib->strlen($new->intro);
                     $newimglen = strlen($new->avatar);
                     if ($basetext === $new->avatar && $basetext === $new->intro) {
@@ -920,20 +927,20 @@
                         $test->status = true;
                     } else {
                         if ($rec->avatar !== $new->avatar) {
-                            $test->error = $db->ErrorMsg();
+                            $test->error = $DB->get_last_error();
                             $test->sql = array($newimglen . ' bytes (binary) transfer failed. Data changed!');
                             $test->status = false;
                         } else {
-                            $test->error = $db->ErrorMsg();
+                            $test->error = $DB->get_last_error();
                             $test->sql = array($newtextlen . ' cc. (text) transfer failed. Data changed!');
                             $test->status = false;
                         }
                     }
                 } else {
-                    $test->error = $db->ErrorMsg();
+                    $test->error = $DB->get_last_error();
                 }
             } else {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['update record '. $textlen . ' cc. (text) and ' . $imglen . ' bytes (binary)'] = $test;
         }
@@ -944,26 +951,26 @@
             $test->status = false;
             $test->sql = array();
         /// Build the record to insert
-            $rec->intro = addslashes($fulltext);
+            $rec->intro = $fulltext;
             $rec->name = 'updatelobs';
         /// Calculate its length
             $textlen = $textlib->strlen($fulltext);
-            if (set_field('newnameforthetable', 'intro', $rec->intro, 'name', $rec->name)) {
-                if ($new = get_record('newnameforthetable', 'id', $rec->id)) {
+            if ($DB->set_field('newnameforthetable', 'intro', $rec->intro, array('name'=>$rec->name))) {
+                if ($new = $DB->get_record('newnameforthetable', array('id'=>$rec->id))) {
                     $newtextlen = $textlib->strlen($new->intro);
                     if ($fulltext === $new->intro) {
                         $test->sql = array($newtextlen . ' cc. (text) sent and received ok');
                         $test->status = true;
                     } else {
-                        $test->error = $db->ErrorMsg();
+                        $test->error = $DB->get_last_error();
                         $test->sql = array($newtextlen . ' cc. (text) transfer failed. Data changed!');
                         $test->status = false;
                     }
                 } else {
-                    $test->error = $db->ErrorMsg();
+                    $test->error = $DB->get_last_error();
                 }
             } else {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['set field '. $textlen . ' cc. (text)'] = $test;
         }
@@ -974,31 +981,31 @@
             $test->status = false;
             $test->sql = array();
         /// Build the record to insert
-            $rec->avatar = addslashes($fulltext);
+            $rec->avatar = $fulltext;
             $rec->name = 'updatelobs';
         /// Calculate its length
             $textlen = strlen($fulltext);
-            if (set_field('newnameforthetable', 'avatar', $rec->avatar, 'name', $rec->name)) {
-                if ($new = get_record('newnameforthetable', 'id', $rec->id)) {
+            if ($DB->set_field('newnameforthetable', 'avatar', $rec->avatar, array('name'=>$rec->name))) {
+                if ($new = $DB->get_record('newnameforthetable', array('id'=>$rec->id))) {
                     $newtextlen = strlen($new->avatar);
                     if ($fulltext === $new->avatar) {
                         $test->sql = array($newtextlen . ' bytes (binary) sent and received ok');
                         $test->status = true;
                     } else {
-                        $test->error = $db->ErrorMsg();
+                        $test->error = $DB->get_last_error();
                         $test->sql = array($newtextlen . ' bytes (binary) transfer failed. Data changed!');
                         $test->status = false;
                     }
                 } else {
-                    $test->error = $db->ErrorMsg();
+                    $test->error = $DB->get_last_error();
                 }
             } else {
-                $test->error = $db->ErrorMsg();
+                $test->error = $DB->get_last_error();
             }
             $tests['set field '. $textlen . ' bytes (binary)'] = $test;
         }
 
-    /// TODO: Check here values of the inserted records to see that everything ha the correct value
+    /// TODO: Check here values of the inserted records to see that everything has the correct value
 
 
     /// Iterate over tests, showing information as needed
Index: admin/xmldb/actions/load_xml_file/load_xml_file.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/load_xml_file/load_xml_file.class.php,v
retrieving revision 1.7
diff -u -r1.7 load_xml_file.class.php
--- admin/xmldb/actions/load_xml_file/load_xml_file.class.php	10 Oct 2007 05:25:26 -0000	1.7
+++ admin/xmldb/actions/load_xml_file/load_xml_file.class.php	15 May 2008 21:10:33 -0000
@@ -95,7 +95,7 @@
                 $loaded = $xmldb_file->loadXMLStructure();
                 if ($loaded && $xmldb_file->isLoaded()) {
                     $dbdir->xml_loaded = true;
-                    $dbdir->filemtime = filemtime($dbdir->path . '/install.xml'); 
+                    $dbdir->filemtime = filemtime($dbdir->path . '/install.xml');
                 }
                 $dbdir->xml_file = $xmldb_file;
             } else {
Index: mod/quiz/report/grading/report.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/report/grading/report.php,v
retrieving revision 1.30
diff -u -r1.30 report.php
--- mod/quiz/report/grading/report.php	15 May 2008 16:02:12 -0000	1.30
+++ mod/quiz/report/grading/report.php	15 May 2008 21:11:29 -0000
@@ -241,11 +241,11 @@
         $table->setup();
 
         // this sql is a join of the attempts table and the user table.  I do this so I can sort by user name and attempt number (not id)
-        $select = 'SELECT '.sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).' AS userattemptid, qa.id AS attemptid, qa.uniqueid, qa.attempt, qa.timefinish, u.id AS userid, u.firstname, u.lastname, u.picture ';
+        $select = 'SELECT '.sql_concat('u.id', '\'#\'', 'COALESCE(qa.attempt, 0)').' AS userattemptid, qa.id AS attemptid, qa.uniqueid, qa.attempt, qa.timefinish, u.id AS userid, u.firstname, u.lastname, u.picture ';
         $from   = 'FROM '.$CFG->prefix.'user u LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON (u.id = qa.userid AND qa.quiz = '.$quiz->id.') ';
         $where  = 'WHERE u.id IN ('.$userids.') ';
-        $where .= 'AND '.$db->IfNull('qa.attempt', '0').' != 0 ';
-        $where .= 'AND '.$db->IfNull('qa.timefinish', '0').' != 0 ';
+        $where .= 'AND COALESCE(qa.attempt, 0) != 0 ';
+        $where .= 'AND COALESCE(qa.timefinish, 0) != 0 ';
         $where .= 'AND preview = 0 '; // ignore previews
 
         if($table->get_sql_where()) { // forgot what this does
@@ -261,7 +261,7 @@
         }
 
         // set up the pagesize
-        $total  = count_records_sql('SELECT COUNT(DISTINCT('.sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).')) '.$from.$where);
+        $total  = count_records_sql('SELECT COUNT(DISTINCT('.sql_concat('u.id', '\'#\'', 'COALESCE(qa.attempt, 0)').')) '.$from.$where);
         $table->pagesize(QUIZ_REPORT_DEFAULT_PAGE_SIZE, $total);
 
         // get the attempts and process them
@@ -348,7 +348,7 @@
         $userids   = implode(',', array_keys($users));
 
         // this sql joins the attempts table and the user table
-        $select = 'SELECT '.sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).' AS userattemptid,
+        $select = 'SELECT '.sql_concat('u.id', '\'#\'', 'COALESCE(qa.attempt, 0)').' AS userattemptid,
                     qa.id AS attemptid, qa.uniqueid, qa.attempt, qa.timefinish, qa.preview,
                     u.id AS userid, u.firstname, u.lastname, u.picture ';
         $from   = 'FROM '.$CFG->prefix.'user u LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON (u.id = qa.userid AND qa.quiz = '.$quiz->id.') ';
@@ -364,8 +364,8 @@
         // ignore previews
         $where .= ' AND preview = 0 ';
 
-        $where .= 'AND '.$db->IfNull('qa.attempt', '0').' != 0 ';
-        $where .= 'AND '.$db->IfNull('qa.timefinish', '0').' != 0 ';
+        $where .= 'AND COALESCE(qa.attempt, 0) != 0 ';
+        $where .= 'AND COALESCE(qa.timefinish, 0) != 0 ';
         $sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
         $attempts = get_records_sql($select.$from.$where.$sort);
 
Index: admin/xmldb/actions/edit_table/edit_table.class.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/xmldb/actions/edit_table/edit_table.class.php,v
retrieving revision 1.5
diff -u -r1.5 edit_table.class.php
--- admin/xmldb/actions/edit_table/edit_table.class.php	10 Oct 2007 05:25:28 -0000	1.5
+++ admin/xmldb/actions/edit_table/edit_table.class.php	15 May 2008 21:10:32 -0000
@@ -103,7 +103,7 @@
 
     /// Add the main form
         $o = '<form id="form" action="index.php" method="post">';
-        $o.= '<div>';        
+        $o.= '<div>';
         $o.= '    <input type="hidden" name ="dir" value="' . str_replace($CFG->dirroot, '', $dirpath) . '" />';
         $o.= '    <input type="hidden" name ="table" value="' . $tableparam .'" />';
         $o.= '    <input type="hidden" name ="action" value="edit_table_save" />';
@@ -150,17 +150,8 @@
         $b .= '</p>';
         $o .= $b;
 
-    /// Join all the reserved words into one big array
-    /// Calculate list of available SQL generators
-        $plugins = get_list_of_plugins('lib/xmldb/classes/generators');
-        $reserved_words = array();
-        foreach($plugins as $plugin) {
-            $classname = 'XMLDB' . $plugin;
-            $generator = new $classname();
-            $reserved_words = array_merge($reserved_words, $generator->getReservedWords());
-        }
-        sort($reserved_words);
-        $reserved_words = array_unique($reserved_words);
+        require("$CFG->libdir/ddl/sql_generator.php");
+        $reserved_words = sql_generator::getAllReservedWords();
 
     /// Delete any 'changeme' field/key/index
         $table->deleteField('changeme');
@@ -205,7 +196,7 @@
                     $b .= '[' . $this->str['delete'] . ']';
                 }
             /// Detect if the table name is a reserved word
-                if (in_array($field->getName(), $reserved_words)) {
+                if (array_key_exists($field->getName(), $reserved_words)) {
                     $b .= '&nbsp;<a href="index.php?action=view_reserved_words"><span class="error">' . $this->str['reserved'] . '</span></a>';
                 }
             /// The readable info
Index: backup/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/backup/lib.php,v
retrieving revision 1.100
diff -u -r1.100 lib.php
--- backup/lib.php	1 May 2008 19:59:29 -0000	1.100
+++ backup/lib.php	15 May 2008 21:10:40 -0000
@@ -326,7 +326,7 @@
     /// This function upgrades the backup tables, if necessary
     /// It's called from admin/index.php, also backup.php and restore.php
 
-        global $CFG, $db, $interactive;
+        global $CFG, $DB, $interactive, $DB;
 
         require_once ("$CFG->dirroot/backup/version.php");  // Get code versions
 
@@ -344,17 +344,17 @@
             upgrade_log_start();
             print_heading('backup');
         if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-            $db->debug=true;
+            $DB->set_debug(true);
         }
 
         /// Both old .sql files and new install.xml are supported
         /// but we priorize install.xml (XMLDB) if present
             $status = false;
             if (file_exists($CFG->dirroot . '/backup/db/install.xml')) {
-                $status = install_from_xmldb_file($CFG->dirroot . '/backup/db/install.xml'); //New method
+                $status = $DB->get_manager()->install_from_xmldb_file($CFG->dirroot . '/backup/db/install.xml'); //New method
             }
         if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-            $db->debug = false;
+            $DB->set_debug(false);
         }
             if ($status) {
                 if (set_config("backup_version", $backup_version) and set_config("backup_release", $backup_release)) {
@@ -402,16 +402,16 @@
             $newupgrade_status = true;
             if ($newupgrade && function_exists($newupgrade_function)) {
             if (!defined('CLI_UPGRADE') || !CLI_UPGRADE) {
-                $db->debug = true;
+                $DB->set_debug(true);
             }
                 $newupgrade_status = $newupgrade_function($CFG->backup_version);
             } else if ($newupgrade) {
                 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
                         '/backup/db/upgrade.php');
             }
-        if (!defined('CLI_UPGRADE') || !CLI_UPGRADE) {
-            $db->debug=false;
-        }
+            if (!defined('CLI_UPGRADE') || !CLI_UPGRADE) {
+                $DB->set_debug(false);
+            }
         /// Now analyze upgrade results
             if ($newupgrade_status) {    // No upgrading failed
                 if (set_config("backup_version", $backup_version) and set_config("backup_release", $backup_release)) {
Index: lib/dml/pdo_moodle_database.php
===================================================================
RCS file: lib/dml/pdo_moodle_database.php
diff -N lib/dml/pdo_moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/pdo_moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,156 @@
+<?php  //$Id:$
+
+require_once($CFG->libdir.'/dml/moodle_database.php');
+require_once($CFG->libdir.'/dml/pdo_moodle_recordset.php');
+
+/**
+ * Experimental pdo database class
+ * @package dmlib
+ */
+abstract class pdo_moodle_database extends moodle_database {
+
+    protected $pdb;
+    protected $columns = array(); // I wish we had a shared memory cache for this :-(
+
+    public function __construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        parent::__construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix);
+    }
+
+    public function connect() {
+        try {
+            $this->pdb = new PDO('mysql:host='.$this->dbhost.';dbname='.$this->dbname, $this->dbuser, $this->pass, array(PDO::ATTR_PERSISTENT => $this->dbpresist));
+            $this->configure_dbconnection();
+            return true;
+        } catch (PDOException $ex) {
+            return false;
+        }
+    }
+
+    protected function configure_dbconnection() {
+    }
+
+    public function get_columns($table) {
+        if (isset($this->columns[$table])) {
+            return $this->columns[$table];
+        }
+
+        if (!$this->columns[$table] = array_change_key_case($this->db->MetaColumns($this->prefix.$table), CASE_LOWER)) {
+            $this->columns[$table] = array();
+        }
+
+        return $this->columns[$table];
+    }
+
+    public function reset_columns($table=null) {
+        if ($table) {
+            unset($this->columns[$table]);
+        } else {
+            $this->columns[$table] = array();
+        }
+    }
+
+
+    protected function report_error($sql, $params, $obj) {
+        debugging($e->getMessage() .'<br /><br />'. s($sql));
+    }
+
+    public function set_debug($state) {
+        //TODO
+    }
+
+    public function set_logging($state) {
+        //TODO
+    }
+
+    public function execute($sql, array $params=null) {
+        try {
+            //$this->reset_columns(); // TODO: do we need to clean the cache here??
+            list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+            $sth = $this->dbh->prepare($sql);
+            return $sth->execute($params);
+        } catch (PDOException $ex) {
+            $this->report_error($sql, $params, $ex);
+            return false;
+        }
+    }
+
+    public function delete_records_select($table, $select, array $params=null) {
+        try {
+            if ($select) {
+                $select = "WHERE $select";
+            }
+            $sql = "DELETE FROM {$this->prefix}$table $select";
+            list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+            $sth = $this->dbh->prepare($sql);
+            return $sth->execute($params);
+        } catch (PDOException $ex) {
+            $this->report_error($sql, $params, $ex);
+            return false;
+        }
+    }
+
+    public function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0) {
+        try {
+            list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+            $sth = $this->dbh->prepare($sql);
+            error('TODO');
+            return $this->create_recordset($sth);
+
+        } catch (PDOException $ex) {
+            $this->report_error($sql, $params, $ex);
+            return false;
+        }
+    }
+
+    protected function create_recordset($sth) {
+        return new pdo_moodle_recordset($sth);
+    }
+
+    public function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnum=0) {
+        try {
+            list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+            error('TODO');
+
+        } catch (PDOException $ex) {
+            $this->report_error($sql, $params, $ex);
+            return false;
+        }
+    }
+
+    public function get_fieldset_sql($sql, array $params=null) {
+        try {
+            list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+            error('TODO');
+
+        } catch (PDOException $ex) {
+            $this->report_error($sql, $params, $ex);
+            return false;
+        }
+    }
+
+    public function sql_substr() {
+        error('TODO');
+    }
+
+    public function sql_concat() {
+        error('TODO');
+    }
+
+    public function sql_concat_join($separator="' '", $elements=array()) {
+        error('TODO');
+    }
+
+    public function begin_sql() {
+        $this->pdb->beginTransaction();
+        return true;
+    }
+    public function commit_sql() {
+        $this->pdb->commit();
+        return true;
+    }
+    public function rollback_sql() {
+        $this->pdb->rollBack();
+        return true;
+    }
+
+}
Index: lib/xmldb/XMLDBTable.class.php
===================================================================
RCS file: lib/xmldb/XMLDBTable.class.php
diff -N lib/xmldb/XMLDBTable.class.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/xmldb/XMLDBTable.class.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,796 @@
+<?php // $Id: XMLDBTable.class.php,v 1.22 2007/10/10 05:25:14 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represent one XMLDB table
+
+class XMLDBTable extends XMLDBObject {
+
+    var $fields;
+    var $keys;
+    var $indexes;
+
+    /**
+     * Creates one new XMLDBTable
+     */
+    function XMLDBTable($name) {
+        parent::XMLDBObject($name);
+        $this->fields = array();
+        $this->keys = array();
+        $this->indexes = array();
+    }
+
+    /**
+     * Add one field to the table, allowing to specify the desired  order
+     * If it's not specified, then the field is added at the end
+     */
+    function addField(&$field, $after=NULL) {
+
+    /// Calculate the previous and next fields
+        $prevfield = NULL;
+        $nextfield = NULL;
+
+        if (!$after) {
+            $allfields =& $this->getFields();
+            if (!empty($allfields)) {
+                end($allfields);
+                $prevfield =& $allfields[key($allfields)];
+            }
+        } else {
+            $prevfield =& $this->getField($after);
+        }
+        if ($prevfield && $prevfield->getNext()) {
+            $nextfield =& $this->getField($prevfield->getNext());
+        }
+
+    /// Set current field previous and next attributes
+        if ($prevfield) {
+            $field->setPrevious($prevfield->getName());
+            $prevfield->setNext($field->getName());
+        }
+        if ($nextfield) {
+            $field->setNext($nextfield->getName());
+            $nextfield->setPrevious($field->getName());
+        }
+    /// Some more attributes
+        $field->setLoaded(true);
+        $field->setChanged(true);
+    /// Add the new field
+        $this->fields[] = $field;
+    /// Reorder the field
+        $this->orderFields($this->fields);
+    /// Recalculate the hash
+        $this->calculateHash(true);
+    /// We have one new field, so the table has changed
+        $this->setChanged(true);
+
+        return $field;
+    }
+
+    /**
+     * Add one key to the table, allowing to specify the desired  order
+     * If it's not specified, then the key is added at the end
+     */
+    function addKey(&$key, $after=NULL) {
+
+    /// Calculate the previous and next keys
+        $prevkey = NULL;
+        $nextkey = NULL;
+
+        if (!$after) {
+            $allkeys =& $this->getKeys();
+            if (!empty($allkeys)) {
+                end($allkeys);
+                $prevkey =& $allkeys[key($allkeys)];
+            }
+        } else {
+            $prevkey =& $this->getKey($after);
+        }
+        if ($prevkey && $prevkey->getNext()) {
+            $nextkey =& $this->getKey($prevkey->getNext());
+        }
+
+    /// Set current key previous and next attributes
+        if ($prevkey) {
+            $key->setPrevious($prevkey->getName());
+            $prevkey->setNext($key->getName());
+        }
+        if ($nextkey) {
+            $key->setNext($nextkey->getName());
+            $nextkey->setPrevious($key->getName());
+        }
+    /// Some more attributes
+        $key->setLoaded(true);
+        $key->setChanged(true);
+    /// Add the new key
+        $this->keys[] = $key;
+    /// Reorder the keys
+        $this->orderKeys($this->keys);
+    /// Recalculate the hash
+        $this->calculateHash(true);
+    /// We have one new field, so the table has changed
+        $this->setChanged(true);
+    }
+
+    /**
+     * Add one index to the table, allowing to specify the desired  order
+     * If it's not specified, then the index is added at the end
+     */
+    function addIndex(&$index, $after=NULL) {
+
+    /// Calculate the previous and next indexes
+        $previndex = NULL;
+        $nextindex = NULL;
+
+        if (!$after) {
+            $allindexes =& $this->getIndexes();
+            if (!empty($allindexes)) {
+                end($allindexes);
+                $previndex =& $allindexes[key($allindexes)];
+            }
+        } else {
+            $previndex =& $this->getIndex($after);
+        }
+        if ($previndex && $previndex->getNext()) {
+            $nextindex =& $this->getIndex($previndex->getNext());
+        }
+
+    /// Set current index previous and next attributes
+        if ($previndex) {
+            $index->setPrevious($previndex->getName());
+            $previndex->setNext($index->getName());
+        }
+        if ($nextindex) {
+            $index->setNext($nextindex->getName());
+            $nextindex->setPrevious($index->getName());
+        }
+
+    /// Some more attributes
+        $index->setLoaded(true);
+        $index->setChanged(true);
+    /// Add the new index
+        $this->indexes[] = $index;
+    /// Reorder the indexes
+        $this->orderIndexes($this->indexes);
+    /// Recalculate the hash
+        $this->calculateHash(true);
+    /// We have one new index, so the table has changed
+        $this->setChanged(true);
+    }
+
+    /**
+     * This function will return the array of fields in the table
+     */
+    function &getFields() {
+        return $this->fields;
+    }
+
+    /**
+     * This function will return the array of keys in the table
+     */
+    function &getKeys() {
+        return $this->keys;
+    }
+
+    /**
+     * This function will return the array of indexes in the table
+     */
+    function &getIndexes() {
+        return $this->indexes;
+    }
+
+    /**
+     * Returns one XMLDBField
+     */
+    function &getField($fieldname) {
+        $i = $this->findFieldInArray($fieldname);
+        if ($i !== NULL) {
+            return $this->fields[$i];
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * Returns the position of one field in the array.
+     */
+    function &findFieldInArray($fieldname) {
+        foreach ($this->fields as $i => $field) {
+            if ($fieldname == $field->getName()) {
+                return $i;
+            }
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * This function will reorder the array of fields
+     */
+    function orderFields() {
+        $result = $this->orderElements($this->fields);
+        if ($result) {
+            $this->setFields($result);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns one XMLDBKey
+     */
+    function &getKey($keyname) {
+        $i = $this->findKeyInArray($keyname);
+        if ($i !== NULL) {
+            return $this->keys[$i];
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * Returns the position of one key in the array.
+     */
+    function &findKeyInArray($keyname) {
+        foreach ($this->keys as $i => $key) {
+            if ($keyname == $key->getName()) {
+                return $i;
+            }
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * This function will reorder the array of keys
+     */
+    function orderKeys() {
+        $result = $this->orderElements($this->keys);
+        if ($result) {
+            $this->setKeys($result);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns one XMLDBIndex
+     */
+    function &getIndex($indexname) {
+        $i = $this->findIndexInArray($indexname);
+        if ($i !== NULL) {
+            return $this->indexes[$i];
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * Returns the position of one index in the array.
+     */
+    function &findIndexInArray($indexname) {
+        foreach ($this->indexes as $i => $index) {
+            if ($indexname == $index->getName()) {
+                return $i;
+            }
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * This function will reorder the array of indexes
+     */
+    function orderIndexes() {
+        $result = $this->orderElements($this->indexes);
+        if ($result) {
+            $this->setIndexes($result);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * This function will set the array of fields in the table
+     */
+    function setFields($fields) {
+        $this->fields = $fields;
+    }
+
+    /**
+     * This function will set the array of keys in the table
+     */
+    function setKeys($keys) {
+        $this->keys = $keys;
+    }
+
+    /**
+     * This function will set the array of indexes in the table
+     */
+    function setIndexes($indexes) {
+        $this->indexes = $indexes;
+    }
+
+    /**
+     * Delete one field from the table
+     */
+    function deleteField($fieldname) {
+
+        $field =& $this->getField($fieldname);
+        if ($field) {
+            $i = $this->findFieldInArray($fieldname);
+            $prevfield = NULL;
+            $nextfield = NULL;
+        /// Look for prev and next field
+            $prevfield =& $this->getField($field->getPrevious());
+            $nextfield =& $this->getField($field->getNext());
+        /// Change their previous and next attributes
+            if ($prevfield) {
+                $prevfield->setNext($field->getNext());
+            }
+            if ($nextfield) {
+                $nextfield->setPrevious($field->getPrevious());
+            }
+        /// Delete the field
+            unset($this->fields[$i]);
+        /// Reorder the whole structure
+            $this->orderFields($this->fields);
+        /// Recalculate the hash
+            $this->calculateHash(true);
+        /// We have one deleted field, so the table has changed
+            $this->setChanged(true);
+        }
+    }
+
+    /**
+     * Delete one key from the table
+     */
+    function deleteKey($keyname) {
+
+        $key =& $this->getKey($keyname);
+        if ($key) {
+            $i = $this->findKeyInArray($keyname);
+            $prevkey = NULL;
+            $nextkey = NULL;
+        /// Look for prev and next key
+            $prevkey =& $this->getKey($key->getPrevious());
+            $nextkey =& $this->getKey($key->getNext());
+        /// Change their previous and next attributes
+            if ($prevkey) {
+                $prevkey->setNext($key->getNext());
+            }
+            if ($nextkey) {
+                $nextkey->setPrevious($key->getPrevious());
+            }
+        /// Delete the key
+            unset($this->keys[$i]);
+        /// Reorder the Keys
+            $this->orderKeys($this->keys);
+        /// Recalculate the hash
+            $this->calculateHash(true);
+        /// We have one deleted key, so the table has changed
+            $this->setChanged(true);
+        }
+    }
+
+    /**
+     * Delete one index from the table
+     */
+    function deleteIndex($indexname) {
+
+        $index =& $this->getIndex($indexname);
+        if ($index) {
+            $i = $this->findIndexInArray($indexname);
+            $previndex = NULL;
+            $nextindex = NULL;
+        /// Look for prev and next index
+            $previndex =& $this->getIndex($index->getPrevious());
+            $nextindex =& $this->getIndex($index->getNext());
+        /// Change their previous and next attributes
+            if ($previndex) {
+                $previndex->setNext($index->getNext());
+            }
+            if ($nextindex) {
+                $nextindex->setPrevious($index->getPrevious());
+            }
+        /// Delete the index
+            unset($this->indexes[$i]);
+        /// Reorder the indexes
+            $this->orderIndexes($this->indexes);
+        /// Recalculate the hash
+            $this->calculateHash(true);
+        /// We have one deleted index, so the table has changed
+            $this->setChanged(true);
+        }
+    }
+
+    /**
+     * Load data from XML to the table
+     */
+    function arr2XMLDBTable($xmlarr) {
+
+        global $CFG;
+
+        $result = true;
+
+    /// Debug the table
+    /// traverse_xmlize($xmlarr);                   //Debug
+    /// print_object ($GLOBALS['traverse_array']);  //Debug
+    /// $GLOBALS['traverse_array']="";              //Debug
+
+    /// Process table attributes (name, comment, previoustable and nexttable)
+        if (isset($xmlarr['@']['NAME'])) {
+            $this->name = trim($xmlarr['@']['NAME']);
+        } else {
+            $this->errormsg = 'Missing NAME attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+        if (isset($xmlarr['@']['COMMENT'])) {
+            $this->comment = trim($xmlarr['@']['COMMENT']);
+        } else if (!empty($CFG->xmldbdisablecommentchecking)) {
+            $this->comment = '';
+        } else {
+            $this->errormsg = 'Missing COMMENT attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+        if (isset($xmlarr['@']['PREVIOUS'])) {
+            $this->previous = trim($xmlarr['@']['PREVIOUS']);
+        }
+        if (isset($xmlarr['@']['NEXT'])) {
+            $this->next = trim($xmlarr['@']['NEXT']);
+        }
+
+    /// Iterate over fields
+        if (isset($xmlarr['#']['FIELDS']['0']['#']['FIELD'])) {
+            foreach ($xmlarr['#']['FIELDS']['0']['#']['FIELD'] as $xmlfield) {
+                if (!$result) { //Skip on error
+                    continue;
+                }
+                $name = trim($xmlfield['@']['NAME']);
+                $field = new XMLDBField($name);
+                $field->arr2XMLDBField($xmlfield);
+                $this->fields[] = $field;
+                if (!$field->isLoaded()) {
+                    $this->errormsg = 'Problem loading field ' . $name;
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            }
+        } else {
+            $this->errormsg = 'Missing FIELDS section';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+    /// Perform some general checks over fields
+        if ($result && $this->fields) {
+        /// Check field names are ok (lowercase, a-z _-)
+            if (!$this->checkNameValues($this->fields)) {
+                $this->errormsg = 'Some FIELDS name values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Check previous & next are ok (duplicates and existing fields)
+            $this->fixPrevNext($this->fields);
+            if ($result && !$this->checkPreviousNextValues($this->fields)) {
+                $this->errormsg = 'Some FIELDS previous/next values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Order fields
+            if ($result && !$this->orderFields($this->fields)) {
+                $this->errormsg = 'Error ordering the fields';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        }
+
+    /// Iterate over keys
+        if (isset($xmlarr['#']['KEYS']['0']['#']['KEY'])) {
+            foreach ($xmlarr['#']['KEYS']['0']['#']['KEY'] as $xmlkey) {
+                if (!$result) { //Skip on error
+                    continue;
+                }
+                $name = trim($xmlkey['@']['NAME']);
+                $key = new XMLDBKey($name);
+                $key->arr2XMLDBKey($xmlkey);
+                $this->keys[] = $key;
+                if (!$key->isLoaded()) {
+                    $this->errormsg = 'Problem loading key ' . $name;
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            }
+        } else {
+            $this->errormsg = 'Missing KEYS section (at least one PK must exist)';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+    /// Perform some general checks over keys
+        if ($result && $this->keys) {
+        /// Check keys names are ok (lowercase, a-z _-)
+            if (!$this->checkNameValues($this->keys)) {
+                $this->errormsg = 'Some KEYS name values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Check previous & next are ok (duplicates and existing keys)
+            $this->fixPrevNext($this->keys);
+            if ($result && !$this->checkPreviousNextValues($this->keys)) {
+                $this->errormsg = 'Some KEYS previous/next values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Order keys
+            if ($result && !$this->orderKeys($this->keys)) {
+                $this->errormsg = 'Error ordering the keys';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// TODO: Only one PK
+        /// TODO: Not keys with repeated fields
+        /// TODO: Check fields and reffieds exist in table
+        }
+
+    /// Iterate over indexes
+        if (isset($xmlarr['#']['INDEXES']['0']['#']['INDEX'])) {
+            foreach ($xmlarr['#']['INDEXES']['0']['#']['INDEX'] as $xmlindex) {
+                if (!$result) { //Skip on error
+                    continue;
+                }
+                $name = trim($xmlindex['@']['NAME']);
+                $index = new XMLDBIndex($name);
+                $index->arr2XMLDBIndex($xmlindex);
+                $this->indexes[] = $index;
+                if (!$index->isLoaded()) {
+                    $this->errormsg = 'Problem loading index ' . $name;
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            }
+        }
+
+    /// Perform some general checks over indexes
+        if ($result && $this->indexes) {
+        /// Check field names are ok (lowercase, a-z _-)
+            if (!$this->checkNameValues($this->indexes)) {
+                $this->errormsg = 'Some INDEXES name values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Check previous & next are ok (duplicates and existing INDEXES)
+            $this->fixPrevNext($this->indexes);
+            if ($result && !$this->checkPreviousNextValues($this->indexes)) {
+                $this->errormsg = 'Some INDEXES previous/next values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Order indexes
+            if ($result && !$this->orderIndexes($this->indexes)) {
+                $this->errormsg = 'Error ordering the indexes';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// TODO: Not indexes with repeated fields
+        /// TODO: Check fields exist in table
+        }
+
+    /// Set some attributes
+        if ($result) {
+            $this->loaded = true;
+        }
+        $this->calculateHash();
+        return $result;
+    }
+
+    /**
+     * This function calculate and set the hash of one XMLDBTable
+     */
+     function calculateHash($recursive = false) {
+        if (!$this->loaded) {
+            $this->hash = NULL;
+        } else {
+            $key = $this->name . $this->comment;
+            if ($this->fields) {
+                foreach ($this->fields as $fie) {
+                    $field =& $this->getField($fie->getName());
+                    if ($recursive) {
+                        $field->calculateHash($recursive);
+                    }
+                    $key .= $field->getHash();
+                }
+            }
+            if ($this->keys) {
+                foreach ($this->keys as $ke) {
+                    $k =& $this->getKey($ke->getName());
+                    if ($recursive) {
+                        $k->calculateHash($recursive);
+                    }
+                    $key .= $k->getHash();
+                }
+            }
+            if ($this->indexes) {
+                foreach ($this->indexes as $in) {
+                    $index =& $this->getIndex($in->getName());
+                    if ($recursive) {
+                        $index->calculateHash($recursive);
+                    }
+                    $key .= $index->getHash();
+                }
+            }
+            $this->hash = md5($key);
+        }
+    }
+
+    /**
+     * This function will output the XML text for one table
+     */
+    function xmlOutput() {
+        $o = '';
+        $o.= '    <TABLE NAME="' . $this->name . '"';
+        if ($this->comment) {
+            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
+        }
+        if ($this->previous) {
+            $o.= ' PREVIOUS="' . $this->previous . '"';
+        }
+        if ($this->next) {
+            $o.= ' NEXT="' . $this->next . '"';
+        }
+            $o.= '>' . "\n";
+    /// Now the fields
+        if ($this->fields) {
+            $o.= '      <FIELDS>' . "\n";
+            foreach ($this->fields as $field) {
+                $o.= $field->xmlOutput();
+            }
+            $o.= '      </FIELDS>' . "\n";
+        }
+    /// Now the keys
+        if ($this->keys) {
+            $o.= '      <KEYS>' . "\n";
+            foreach ($this->keys as $key) {
+                $o.= $key->xmlOutput();
+            }
+            $o.= '      </KEYS>' . "\n";
+        }
+    /// Now the indexes
+        if ($this->indexes) {
+            $o.= '      <INDEXES>' . "\n";
+            foreach ($this->indexes as $index) {
+                $o.= $index->xmlOutput();
+            }
+            $o.= '      </INDEXES>' . "\n";
+        }
+        $o.= '    </TABLE>' . "\n";
+
+        return $o;
+    }
+
+    /**
+     * This function will add one new field to the table with all
+     * its attributes defined
+     *
+     * @param string name name of the field
+     * @param string type XMLDB_TYPE_INTEGER, XMLDB_TYPE_NUMBER, XMLDB_TYPE_CHAR, XMLDB_TYPE_TEXT, XMLDB_TYPE_BINARY
+     * @param string precision length for integers and chars, two-comma separated numbers for numbers and 'small', 'medium', 'big' for texts and binaries
+     * @param string unsigned XMLDB_UNSIGNED or null (or false)
+     * @param string notnull XMLDB_NOTNULL or null (or false)
+     * @param string sequence XMLDB_SEQUENCE or null (or false)
+     * @param string enum XMLDB_ENUM or null (or false)
+     * @param array enumvalues an array of possible values if XMLDB_ENUM is set
+     * @param string default meaningful default o null (or false)
+     * @param string previous name of the previous field in the table or null (or false)
+     */
+    function addFieldInfo($name, $type, $precision=null, $unsigned=null, $notnull=null, $sequence=null, $enum=null, $enumvalues=null, $default=null, $previous=null) {
+        $field = new XMLDBField($name);
+        $field->setAttributes($type, $precision, $unsigned, $notnull, $sequence, $enum, $enumvalues, $default);
+        $this->addField($field, $previous);
+
+        return $field;
+    }
+
+    /**
+     * This function will add one new key to the table with all
+     * its attributes defined
+     *
+     * @param string name name of the key
+     * @param string type XMLDB_KEY_PRIMARY, XMLDB_KEY_UNIQUE, XMLDB_KEY_FOREIGN
+     * @param array fields an array of fieldnames to build the key over
+     * @param string reftable name of the table the FK points to or null
+     * @param array reffields an array of fieldnames in the FK table or null
+     */
+    function addKeyInfo($name, $type, $fields, $reftable=null, $reffields=null) {
+        $key = new XMLDBKey($name);
+        $key->setAttributes($type, $fields, $reftable, $reffields);
+        $this->addKey($key);
+    }
+
+    /**
+     * This function will add one new index to the table with all
+     * its attributes defined
+     *
+     * @param string name name of the index
+     * @param string type XMLDB_INDEX_UNIQUE, XMLDB_INDEX_NOTUNIQUE
+     * @param array fields an array of fieldnames to build the index over
+     */
+    function addIndexInfo($name, $type, $fields) {
+        $index = new XMLDBIndex($name);
+        $index->setAttributes($type, $fields);
+        $this->addIndex($index);
+    }
+
+    /**
+     * This function will return all the errors found in one table
+     * looking recursively inside each field/key/index. Returns
+     * an array of errors or false
+     */
+    function getAllErrors() {
+
+        $errors = array();
+    /// First the table itself
+        if ($this->getError()) {
+            $errors[] = $this->getError();
+        }
+    /// Delegate to fields
+        if ($fields = $this->getFields()) {
+            foreach ($fields as $field) {
+                if ($field->getError()) {
+                    $errors[] = $field->getError();
+                }
+            }
+        }
+    /// Delegate to keys
+        if ($keys = $this->getKeys()) {
+            foreach ($keys as $key) {
+                if ($key->getError()) {
+                    $errors[] = $key->getError();
+                }
+            }
+        }
+    /// Delegate to indexes
+        if ($indexes = $this->getIndexes()) {
+            foreach ($indexes as $index) {
+                if ($index->getError()) {
+                    $errors[] = $index->getError();
+                }
+            }
+        }
+    /// Return decision
+        if (count($errors)) {
+            return $errors;
+        } else {
+            return false;
+        }
+    }
+}
+
+?>
Index: lib/dml/postgres7_adodb_moodle_database.php
===================================================================
RCS file: lib/dml/postgres7_adodb_moodle_database.php
diff -N lib/dml/postgres7_adodb_moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/postgres7_adodb_moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,401 @@
+<?php  //$Id:$
+
+require_once($CFG->libdir.'/dml/moodle_database.php');
+require_once($CFG->libdir.'/dml/adodb_moodle_database.php');
+
+/**
+ * Postgresql database class using adodb backend
+ * @package dmlib
+ */
+class postgres7_adodb_moodle_database extends adodb_moodle_database {
+    function __construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        if ($prefix=='') {
+            print_error('prefixcannotbeempty', 'debug', '', array($prefix, $this->get_dbfamily()));
+        }
+        parent::__construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix);
+    }
+
+    /**
+     * Returns database family type
+     * @return string db family name (mysql, postgres, mssql, oracle, etc.)
+     */
+    public function get_dbfamily() {
+        return 'postgres';
+    }
+
+    /**
+     * Returns database type
+     * @return string db type mysql, mysqli, postgres7
+     */
+    protected function get_dbtype() {
+        return 'postgres7';
+    }
+
+    /**
+     * Returns supported query parameter types
+     * @return bitmask
+     */
+    protected function allowed_param_types() {
+        return SQL_PARAMS_QM;
+    }
+
+    public function get_columns($table) {
+        if (isset($this->columns[$table])) {
+            return $this->columns[$table];
+        }
+
+        if (!$columns = $this->db->MetaColumns($this->prefix.$table)) {
+            return array();
+        }
+
+        $this->columns[$table] = array();
+
+        foreach ($columns as $column) {
+            // colum names must be lowercase
+            $column->meta_type = substr($this->db->MetaType($column), 0 ,1); // only 1 character
+            if ($column->has_default) {
+                if ($pos = strpos($column->default_value, '::')) {
+                    if (strpos($column->default_value, "'") === 0) {
+                        $column->default_value = substr($column->default_value, 1, $pos-2);
+                    } else {
+                        $column->default_value = substr($column->default_value, 0, $pos);
+                    }
+                }
+            } else {
+                $column->default_value = null;
+            }
+            $this->columns[$table][$column->name] = new database_column_info($column);
+        }
+
+        return $this->columns[$table];
+    }
+
+    protected function configure_dbconnection() {
+        if (!defined('ADODB_ASSOC_CASE')) {
+            define ('ADODB_ASSOC_CASE', 2);
+        }
+
+        $this->db->SetFetchMode(ADODB_ASSOC_CASE);
+        $this->db->Execute("SET NAMES 'utf8'");
+
+        return true;
+    }
+
+    /**
+     * This method will introspect inside DB to detect it it's a UTF-8 DB or no
+     * Used from setup.php to set correctly "set names" when the installation
+     * process is performed without the initial and beautiful installer
+     * @return bool true if db in unicode mode
+     */
+    function setup_is_unicodedb() {
+    /// Get PostgreSQL server_encoding value
+        $rs = $this->db->Execute("SHOW server_encoding");
+        if ($rs && !$rs->EOF) {
+            $encoding = $rs->fields['server_encoding'];
+            if (strtoupper($encoding) == 'UNICODE' || strtoupper($encoding) == 'UTF8') {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Insert new record into database, as fast as possible, no safety checks, lobs not supported.
+     * @param string $table name
+     * @param mixed $params data record as object or array
+     * @param bool $returnit return it of inserted record
+     * @param bool $bulk true means repeated inserts expected
+     * @return mixed success or new id
+     */
+    public function insert_record_raw($table, $params, $returnid=true, $bulk=false) {
+    /// Postgres doesn't have the concept of primary key built in
+    /// and will return the OID which isn't what we want.
+    /// The efficient and transaction-safe strategy is to
+    /// move the sequence forward first, and make the insert
+    /// with an explicit id.
+
+        if (!is_array($params)) {
+            $params = (array)$params;
+        }
+        unset($params['id']);
+        if ($returnid) {
+            if ($nextval = $this->get_field_sql("SELECT NEXTVAL('{$this->prefix}{$table}_id_seq')")) {
+                $params['id'] = (int)$nextval;
+            }
+        }
+
+        if (empty($params)) {
+            return false;
+        }
+
+        $fields = implode(',', array_keys($params));
+        $qms    = array_fill(0, count($params), '?');
+        $qms    = implode(',', $qms);
+
+        $sql = "INSERT INTO {$this->prefix}$table ($fields) VALUES($qms)";
+
+        if (!$rs = $this->db->Execute($sql, $params)) {
+            $this->report_error($sql, $params);
+            return false;
+        }
+        if (!$returnid) {
+            return true;
+        }
+        if (!empty($params['id'])) {
+            return (int)$params['id'];
+        }
+
+        $oid = $this->db->Insert_ID();
+
+        // try to get the primary key based on id
+        $sql = "SELECT id FROM {$this->prefix}$table WHERE oid = $oid";
+        if ( ($rs = $this->db->Execute($sql))
+             && ($rs->RecordCount() == 1) ) {
+            trigger_error("Retrieved id using oid on table $table because we could not find the sequence.");
+            return (integer)reset($rs->fields);
+        }
+        trigger_error("Failed to retrieve primary key after insert: $sql");
+        return false;
+    }
+
+    /**
+     * Insert a record into a table and return the "id" field if required,
+     * Some conversions and safety checks are carried out. Lobs are supported.
+     * If the return ID isn't required, then this just reports success as true/false.
+     * $data is an object containing needed data
+     * @param string $table The database table to be inserted into
+     * @param object $data A data object with values for one or more fields in the record
+     * @param bool $returnid Should the id of the newly created record entry be returned? If this option is not requested then true/false is returned.
+     * @param bool $bulk true means repeated inserts expected
+     * @return mixed success or new ID
+     */
+    public function insert_record($table, $dataobject, $returnid=true, $bulk=false) {
+        //TODO: add support for blobs BYTEA
+        if (!is_object($dataobject)) {
+            $dataobject = (object)$dataobject;
+        }
+
+        $columns = $this->get_columns($table);
+        unset($dataobject->id);
+        $cleaned = array();
+        $blobs   = array();
+
+        foreach ($dataobject as $field=>$value) {
+            if (!isset($columns[$field])) {
+                continue;
+            }
+            $column = $columns[$field];
+            if ($column->meta_type == 'B') {
+                if (is_null($value)) {
+                    $cleaned[$field] = null;
+                } else {
+                    $blobs[$field] = $value;
+                    $cleaned[$field] = '@#BLOB#@';
+                }
+                continue;
+
+            } else if (is_bool($value)) {
+                $value = (int)$value; // prevent false '' problems
+
+            } else if ($value === '') {
+                if ($column->meta_type == 'I' or $column->meta_type == 'F' or $column->meta_type == 'N') {
+                    $value = 0; // prevent '' problems in numeric fields
+                }
+            }
+
+            $cleaned[$field] = $value;
+        }
+
+        if (empty($cleaned)) {
+            return false;
+        }
+
+        if (empty($blobs)) {
+            return $this->insert_record_raw($table, $cleaned, $returnid, $bulk);
+        }
+
+        if (!$id = $this->insert_record_raw($table, $cleaned, true, $bulk)) {
+            return false;
+        }
+
+        foreach ($blobs as $key=>$value) {
+            if (!$this->db->UpdateBlob($this->prefix.$table, $key, $value, "id = $id", 'BLOB')) { // adodb does not use bound parameters for blob updates :-(
+                return false;
+            }
+        }
+
+        return ($returnid ? $id : true);
+    }
+
+    /**
+     * Update a record in a table
+     *
+     * $dataobject is an object containing needed data
+     * Relies on $dataobject having a variable "id" to
+     * specify the record to update
+     *
+     * @param string $table The database table to be checked against.
+     * @param object $dataobject An object with contents equal to fieldname=>fieldvalue. Must have an entry for 'id' to map to the table specified.
+     * @param bool true means repeated updates expected
+     * @return bool success
+     */
+    public function update_record($table, $dataobject, $bulk=false) {
+        //TODO: add support for blobs BYTEA
+        if (!is_object($dataobject)) {
+            $dataobject = (object)$dataobject;
+        }
+
+        if (!isset($dataobject->id) ) {
+            return false;
+        }
+        $id = $dataobject->id;
+
+        $columns = $this->get_columns($table);
+        $cleaned = array();
+        $blobs   = array();
+
+        foreach ($dataobject as $field=>$value) {
+            if (!isset($columns[$field])) {
+                continue;
+            }
+            $column = $columns[$field];
+            if ($column->meta_type == 'B') {
+                if (is_null($value)) {
+                    $cleaned[$field] = null;
+                } else {
+                    $blobs[$field] = $value;
+                    $cleaned[$field] = '@#BLOB#@';
+                }
+                continue;
+
+            } else if (is_bool($value)) {
+                $value = (int)$value; // prevent "false" problems
+
+            } else if ($value === '') {
+                if ($column->meta_type == 'I' or $column->meta_type == 'F' or $column->meta_type == 'N') {
+                    $value = 0; // prevent '' problems in numeric fields
+                }
+            }
+            $cleaned[$field] = $value;
+        }
+
+        if (!$this->update_record_raw($table, $cleaned, $bulk)) {
+            return false;
+        }
+
+        if (empty($blobs)) {
+            return true;
+        }
+
+        foreach ($blobs as $key=>$value) {
+            if (!$this->db->UpdateBlob($this->prefix.$table, $key, $value, "id = $id", 'BLOB')) { // adodb does not use bound parameters for blob updates :-(
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Set a single field in every table row where the select statement evaluates to true.
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $newfield the field to set.
+     * @param string $newvalue the value to set the field to.
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @return bool success
+     */
+    public function set_field_select($table, $newfield, $newvalue, $select, array $params=null) {
+        $params = (array)$params;
+        list($select, $params, $type) = $this->fix_sql_params($select, $params);
+
+        $columns = $this->get_columns($table);
+        $column = $columns[$newfield];
+
+        if ($column->meta_type == 'B') {
+            /// update blobs and return
+            $select = $this->emulate_bound_params($select, $params); // adodb does not use bound parameters for blob updates :-(
+            if (!$this->db->UpdateBlob($this->prefix.$table, $newfield, $newvalue, $select, 'BLOB')) {
+                return false;
+            }
+            return true;
+        }
+
+        if ($select) {
+            $select = "WHERE $select";
+        }
+
+        /// normal field update
+        if (is_null($newvalue)) {
+            $newfield = "$newfield = NULL";
+        } else {
+            if (is_bool($newvalue)) {
+                $newvalue = (int)$newvalue; // prevent "false" problems
+            } else if ($newvalue === '') {
+                if ($column->meta_type == 'I' or $column->meta_type == 'F' or $column->meta_type == 'N') {
+                    $newvalue = 0; // prevent '' problems in numeric fields
+                }
+            }
+
+            $newfield = "$newfield = ?";
+            array_unshift($params, $newvalue); // add as first param
+        }
+        $sql = "UPDATE {$this->prefix}$table SET $newfield $select";
+
+        if (!$rs = $this->db->Execute($sql, $params)) {
+            $this->report_error($sql, $params);
+            return false;
+        }
+
+        return true;
+    }
+
+    public function sql_ilike() {
+        return 'ILIKE';
+    }
+
+    public function sql_concat() {
+        $args = func_get_args();
+    /// PostgreSQL requires at least one char element in the concat, let's add it
+    /// here (at the beginning of the array) until ADOdb fixes it
+        if (is_array($args)) {
+            array_unshift($args , "''");
+        }
+        return call_user_func_array(array($this->db, 'Concat'), $args);
+    }
+
+    public function sql_bitxor($int1, $int2) {
+        return '(' . sql_bitor($int1, $int2) . ' - ' . sql_bitand($int1, $int2) . ')';
+    }
+
+    public function sql_cast_char2int($fieldname, $text=false) {
+        return ' CAST(' . $fieldname . ' AS INT) ';
+    }
+
+    /**
+     * Very ugly hack which emulates bound parameters in pg queries
+     * where params not supported :-(
+     */
+    private function emulate_bound_params($sql, array $params=null) {
+        if (empty($params)) {
+            return $sql;
+        }
+        // ok, we have verified sql statement with ? and correct number of params
+        $return = strtok($sql, '?');
+        foreach ($params as $param) {
+            if (is_bool($param)) {
+                $return .= (int)$param;
+            } else if (is_null($param)) {
+                $return .= 'NULL';
+            } else if (is_numeric($param)) {
+                $return .= $param;
+            } else {
+                $param = $this->db->qstr($param);
+                $return .= "$param";
+            }
+            $return .= strtok('?');
+        }
+        return $return;
+    }
+}
Index: lib/dml/oci8po_adodb_moodle_recordset.php
===================================================================
RCS file: lib/dml/oci8po_adodb_moodle_recordset.php
diff -N lib/dml/oci8po_adodb_moodle_recordset.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/oci8po_adodb_moodle_recordset.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * Oracle moodle recordest with special hacks
+ * @package dmlib
+ */
+class oci8po_adodb_moodle_recordset implements adodb_moodle_recordset {
+    private $rs;
+
+    public function __construct($rs) {
+        $this->rs = $rs;
+    }
+
+    public function current() {
+        /// Really DIRTY HACK for Oracle - needed because it can not see difference from NULL and ''
+        /// this can not be removed even if we chane db defaults :-(
+        $fields = $this->rs->fields;
+        array_walk($fields, 'onespace2empty');
+        return (object)$fields;
+    }
+
+    public function key() {
+        return $this->rs->_currentRow;
+    }
+
+    public function next() {
+        $this->rs->MoveNext();
+    }
+
+    public function rewind() {
+        $this->rs->MoveFirst();
+    }
+
+    public function valid() {
+        return !$this->rs->EOF;
+    }
+
+    public function close() {
+        $this->rs->Close();
+    }
+}
Index: lib/xmldb/XMLDBKey.class.php
===================================================================
RCS file: lib/xmldb/XMLDBKey.class.php
diff -N lib/xmldb/XMLDBKey.class.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/xmldb/XMLDBKey.class.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,457 @@
+<?php // $Id: XMLDBKey.class.php,v 1.8 2007/10/10 05:25:14 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represent one XMLDB Key
+
+class XMLDBKey extends XMLDBObject {
+
+    var $type;
+    var $fields;
+    var $reftable;
+    var $reffields;
+
+    /**
+     * Creates one new XMLDBKey
+     */
+    function XMLDBKey($name) {
+        parent::XMLDBObject($name);
+        $this->type = NULL;
+        $this->fields = array();
+        $this->reftable = NULL;
+        $this->reffields = array();
+    }
+
+    /**
+     * Set all the attributes of one XMLDBKey
+     *
+     * @param string type XMLDB_KEY_PRIMARY, XMLDB_KEY_UNIQUE, XMLDB_KEY_FOREIGN
+     * @param array fields an array of fieldnames to build the key over
+     * @param string reftable name of the table the FK points to or null
+     * @param array reffields an array of fieldnames in the FK table or null
+     */
+    function setAttributes($type, $fields, $reftable=null, $reffields=null) {
+        $this->type = $type;
+        $this->fields = $fields;
+        $this->reftable = $reftable;
+        $this->reffields = $reffields;
+    }
+
+    /**
+     * Get the key type
+     */
+    function getType() {
+        return $this->type;
+    }
+
+    /**
+     * Set the key type
+     */
+    function setType($type) {
+        $this->type = $type;
+    }
+
+    /**
+     * Set the key fields
+     */
+    function setFields($fields) {
+        $this->fields = $fields;
+    }
+
+    /**
+     * Set the key reftable
+     */
+    function setRefTable($reftable) {
+        $this->reftable = $reftable;
+    }
+
+    /**
+     * Set the key reffields
+     */
+    function setRefFields($reffields) {
+        $this->reffields = $reffields;
+    }
+
+    /**
+     * Get the key fields
+     */
+    function &getFields() {
+        return $this->fields;
+    }
+
+    /**
+     * Get the key reftable
+     */
+    function &getRefTable() {
+        return $this->reftable;
+    }
+
+    /**
+     * Get the key reffields
+     */
+    function &getRefFields() {
+        return $this->reffields;
+    }
+
+    /**
+     * Load data from XML to the key
+     */
+    function arr2XMLDBKey($xmlarr) {
+
+        $result = true;
+
+    /// Debug the table
+    /// traverse_xmlize($xmlarr);                   //Debug
+    /// print_object ($GLOBALS['traverse_array']);  //Debug
+    /// $GLOBALS['traverse_array']="";              //Debug
+
+    /// Process key attributes (name, type, fields, reftable,
+    /// reffields, comment, previous, next)
+        if (isset($xmlarr['@']['NAME'])) {
+            $this->name = trim($xmlarr['@']['NAME']);
+        } else {
+            $this->errormsg = 'Missing NAME attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+        if (isset($xmlarr['@']['TYPE'])) {
+        /// Check for valid type
+            $type = $this->getXMLDBKeyType(trim($xmlarr['@']['TYPE']));
+            if ($type) {
+                $this->type = $type;
+            } else {
+                $this->errormsg = 'Invalid TYPE attribute';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        } else {
+            $this->errormsg = 'Missing TYPE attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+        if (isset($xmlarr['@']['FIELDS'])) {
+            $fields = strtolower(trim($xmlarr['@']['FIELDS']));
+            if ($fields) {
+                $fieldsarr = explode(',',$fields);
+                if ($fieldsarr) {
+                    foreach ($fieldsarr as $key => $element) {
+                        $fieldsarr [$key] = trim($element);
+                    }
+                } else {
+                    $this->errormsg = 'Incorrect FIELDS attribute (comma separated of fields)';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            } else {
+                $this->errormsg = 'Empty FIELDS attribute';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        } else {
+            $this->errormsg = 'Missing FIELDS attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+    /// Finally, set the array of fields
+        $this->fields = $fieldsarr;
+
+        if (isset($xmlarr['@']['REFTABLE'])) {
+        /// Check we are in a FK
+            if ($this->type == XMLDB_KEY_FOREIGN ||
+                $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
+                $reftable = strtolower(trim($xmlarr['@']['REFTABLE']));
+                if (!$reftable) {
+                    $this->errormsg = 'Empty REFTABLE attribute';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            } else {
+                $this->errormsg = 'Wrong REFTABLE attribute (only FK can have it)';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        } else if ($this->type == XMLDB_KEY_FOREIGN ||
+                   $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
+            $this->errormsg = 'Missing REFTABLE attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+    /// Finally, set the reftable
+        if ($this->type == XMLDB_KEY_FOREIGN ||
+            $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
+            $this->reftable = $reftable;
+        }
+
+        if (isset($xmlarr['@']['REFFIELDS'])) {
+        /// Check we are in a FK
+            if ($this->type == XMLDB_KEY_FOREIGN ||
+                $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
+                $reffields = strtolower(trim($xmlarr['@']['REFFIELDS']));
+                if ($reffields) {
+                    $reffieldsarr = explode(',',$reffields);
+                    if ($reffieldsarr) {
+                        foreach ($reffieldsarr as $key => $element) {
+                            $reffieldsarr [$key] = trim($element);
+                        }
+                    } else {
+                        $this->errormsg = 'Incorrect REFFIELDS attribute (comma separated of fields)';
+                        $this->debug($this->errormsg);
+                        $result = false;
+                    }
+                } else {
+                    $this->errormsg = 'Empty REFFIELDS attribute';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            } else {
+                $this->errormsg = 'Wrong REFFIELDS attribute (only FK can have it)';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        } else if ($this->type == XMLDB_KEY_FOREIGN ||
+                   $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
+            $this->errormsg = 'Missing REFFIELDS attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+    /// Finally, set the array of reffields
+        if ($this->type == XMLDB_KEY_FOREIGN ||
+            $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
+            $this->reffields = $reffieldsarr;
+        }
+
+        if (isset($xmlarr['@']['COMMENT'])) {
+            $this->comment = trim($xmlarr['@']['COMMENT']);
+        }
+
+        if (isset($xmlarr['@']['PREVIOUS'])) {
+            $this->previous = trim($xmlarr['@']['PREVIOUS']);
+        }
+
+        if (isset($xmlarr['@']['NEXT'])) {
+            $this->next = trim($xmlarr['@']['NEXT']);
+        }
+
+    /// Set some attributes
+        if ($result) {
+            $this->loaded = true;
+        }
+        $this->calculateHash();
+        return $result;
+    }
+
+    /**
+     * This function returns the correct XMLDB_KEY_XXX value for the
+     * string passed as argument
+     */
+    function getXMLDBKeyType($type) {
+
+        $result = XMLDB_KEY_INCORRECT;
+
+        switch (strtolower($type)) {
+            case 'primary':
+                $result = XMLDB_KEY_PRIMARY;
+                break;
+            case 'unique':
+                $result = XMLDB_KEY_UNIQUE;
+                break;
+            case 'foreign':
+                $result = XMLDB_KEY_FOREIGN;
+                break;
+            case 'foreign-unique':
+                $result = XMLDB_KEY_FOREIGN_UNIQUE;
+                break;
+        /// case 'check':  //Not supported
+        ///     $result = XMLDB_KEY_CHECK;
+        ///     break;
+        }
+    /// Return the normalized XMLDB_KEY
+        return $result;
+    }
+
+    /**
+     * This function returns the correct name value for the
+     * XMLDB_KEY_XXX passed as argument
+     */
+    function getXMLDBKeyName($type) {
+
+        $result = '';
+
+        switch (strtolower($type)) {
+            case XMLDB_KEY_PRIMARY:
+                $result = 'primary';
+                break;
+            case XMLDB_KEY_UNIQUE:
+                $result = 'unique';
+                break;
+            case XMLDB_KEY_FOREIGN:
+                $result = 'foreign';
+                break;
+            case XMLDB_KEY_FOREIGN_UNIQUE:
+                $result = 'foreign-unique';
+                break;
+        /// case XMLDB_KEY_CHECK:  //Not supported
+        ///     $result = 'check';
+        ///     break;
+        }
+    /// Return the normalized name
+        return $result;
+    }
+
+    /**
+     * This function calculate and set the hash of one XMLDBKey
+     */
+     function calculateHash($recursive = false) {
+        if (!$this->loaded) {
+            $this->hash = NULL;
+        } else {
+            $key = $this->type . implode(', ', $this->fields);
+            if ($this->type == XMLDB_KEY_FOREIGN ||
+                $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
+                $key .= $this->reftable . implode(', ', $this->reffields);
+            }
+                    ;
+            $this->hash = md5($key);
+        }
+    }
+
+    /**
+     *This function will output the XML text for one key
+     */
+    function xmlOutput() {
+        $o = '';
+        $o.= '        <KEY NAME="' . $this->name . '"';
+        $o.= ' TYPE="' . $this->getXMLDBKeyName($this->type) . '"';
+        $o.= ' FIELDS="' . implode(', ', $this->fields) . '"';
+        if ($this->type == XMLDB_KEY_FOREIGN ||
+            $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
+            $o.= ' REFTABLE="' . $this->reftable . '"';
+            $o.= ' REFFIELDS="' . implode(', ', $this->reffields) . '"';
+        }
+        if ($this->comment) {
+            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
+        }
+        if ($this->previous) {
+            $o.= ' PREVIOUS="' . $this->previous . '"';
+        }
+        if ($this->next) {
+            $o.= ' NEXT="' . $this->next . '"';
+        }
+        $o.= '/>' . "\n";
+
+        return $o;
+    }
+
+    /**
+     * This function will set all the attributes of the XMLDBKey object
+     * based on information passed in one ADOkey
+     */
+    function setFromADOKey($adokey) {
+
+    /// Calculate the XMLDB_KEY
+        switch (strtolower($adokey['name'])) {
+            case 'primary':
+                $this->type = XMLDB_KEY_PRIMARY;
+                break;
+            default:
+                $this->type = XMLDB_KEY_UNIQUE;
+        }
+    /// Set the fields, converting all them to lowercase
+        $fields = array_flip(array_change_key_case(array_flip($adokey['columns'])));
+        $this->fields = $fields;
+    /// Some more fields
+        $this->loaded = true;
+        $this->changed = true;
+    }
+
+    /**
+     * Returns the PHP code needed to define one XMLDBKey
+     */
+    function getPHP() {
+
+        $result = '';
+
+    /// The type
+        switch ($this->getType()) {
+            case XMLDB_KEY_PRIMARY:
+                $result .= 'XMLDB_KEY_PRIMARY' . ', ';
+                break;
+            case XMLDB_KEY_UNIQUE:
+                $result .= 'XMLDB_KEY_UNIQUE' . ', ';
+                break;
+            case XMLDB_KEY_FOREIGN:
+                $result .= 'XMLDB_KEY_FOREIGN' . ', ';
+                break;
+        }
+    /// The fields
+        $keyfields = $this->getFields();
+        if (!empty($keyfields)) {
+            $result .= 'array(' . "'".  implode("', '", $keyfields) . "')";
+        } else {
+            $result .= 'null';
+        }
+    /// The FKs attributes
+        if ($this->getType() == XMLDB_KEY_FOREIGN) {
+        /// The reftable
+            $reftable = $this->getRefTable();
+            if (!empty($reftable)) {
+                $result .= ", '" . $reftable . "', ";
+            } else {
+                $result .= 'null, ';
+            }
+        /// The reffields
+            $reffields = $this->getRefFields();
+            if (!empty($reffields)) {
+                $result .= 'array(' . "'".  implode("', '", $reffields) . "')";
+            } else {
+                $result .= 'null';
+            }
+        }
+    /// Return result
+        return $result;
+    }
+
+    /**
+     * Shows info in a readable format
+     */
+    function readableInfo() {
+        $o = '';
+    /// type
+        $o .= $this->getXMLDBKeyName($this->type);
+    /// fields
+        $o .= ' (' . implode(', ', $this->fields) . ')';
+    /// foreign key
+        if ($this->type == XMLDB_KEY_FOREIGN ||
+            $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
+            $o .= ' references ' . $this->reftable . ' (' . implode(', ', $this->reffields) . ')';
+        }
+
+        return $o;
+    }
+}
+
+?>
Index: lib/dmllib_todo.php
===================================================================
RCS file: lib/dmllib_todo.php
diff -N lib/dmllib_todo.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dmllib_todo.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1298 @@
+<?php  //$Id:$
+
+/// FUNCTIONS FOR DATABASE HANDLING  ////////////////////////////////
+
+/**
+ * Execute a given sql command string
+ *
+ * Completely general function - it just runs some SQL and reports success.
+ *
+ * @uses $db
+ * @param string $command The sql string you wish to be executed.
+ * @param bool $feedback Set this argument to true if the results generated should be printed. Default is true.
+ * @return bool success
+ */
+function execute_sql($command, $feedback=true) {
+/// Completely general function - it just runs some SQL and reports success.
+
+    global $db, $CFG, $DB;
+
+    $olddebug = $db->debug;
+
+    if (!$feedback) {
+        if ( !defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
+        $db->debug = false;
+    }
+    }
+
+    if ($CFG->version >= 2006101007) { //Look for trailing ; from Moodle 1.7.0
+        $command = trim($command);
+    /// If the trailing ; is there, fix and warn!
+        if (substr($command, strlen($command)-1, 1) == ';') {
+        /// One noticeable exception, Oracle PL/SQL blocks require ending in ";"
+            if ($CFG->dbfamily == 'oracle' && substr($command, -4) == 'END;') {
+                /// Nothing to fix/warn. The command is one PL/SQL block, so it's ok.
+            } else {
+                $command = trim($command, ';');
+                debugging('Warning. Avoid to end your SQL commands with a trailing ";".', DEBUG_DEVELOPER);
+            }
+        }
+    }
+
+    $DB->reset_columns();  // Clear out the cache, just in case changes were made to table structures
+
+    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+    $rs = $db->Execute($command);
+
+    $db->debug = $olddebug;
+
+    if ($rs) {
+        if ($feedback) {
+            notify(get_string('success'), 'notifysuccess');
+        }
+        return true;
+    } else {
+        if ($feedback) {
+            if ( defined('CLI_UPGRADE') && CLI_UPGRADE ) {
+                notify (get_string('error'));
+            } else {
+            notify('<strong>' . get_string('error') . '</strong>');
+            }
+        }
+        // these two may go to difference places
+        debugging($db->ErrorMsg() .'<br /><br />'. s($command));
+        if (!empty($CFG->dblogerror)) {
+            $debug=array_shift(debug_backtrace());
+            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $command");
+        }
+        return false;
+    }
+}
+
+
+/**
+ * Test whether any records exists in a table which match a particular WHERE clause.
+ *
+ * @uses $CFG
+ * @param string $table The database table to be checked against.
+ * @param string $select A fragment of SQL to be used in a WHERE clause in the SQL call.
+ * @return bool true if a matching record exists, else false.
+ */
+function record_exists_select($table, $select='') {
+
+    global $CFG;
+
+    if ($select) {
+        $select = 'WHERE '.$select;
+    }
+
+    return record_exists_sql('SELECT * FROM '. $CFG->prefix . $table . ' ' . $select);
+}
+
+/**
+ * Test whether a SQL SELECT statement returns any records.
+ *
+ * This function returns true if the SQL statement executes
+ * without any errors and returns at least one record.
+ *
+ * @param string $sql The SQL statement to execute.
+ * @return bool true if the SQL executes without errors and returns at least one record.
+ */
+function record_exists_sql($sql) {
+
+    $limitfrom = 0; /// Number of records to skip
+    $limitnum  = 1; /// Number of records to retrieve
+
+    if (!$rs = get_recordset_sql($sql, $limitfrom, $limitnum)) {
+        return false;
+    }
+
+    if (rs_EOF($rs)) {
+        $result = false;
+    } else {
+        $result = true;
+    }
+
+    rs_close($rs);
+    return $result;
+}
+
+/**
+ * Count the records in a table which match a particular WHERE clause.
+ *
+ * @uses $CFG
+ * @param string $table The database table to be checked against.
+ * @param string $select A fragment of SQL to be used in a WHERE clause in the SQL call.
+ * @param string $countitem The count string to be used in the SQL call. Default is COUNT(*).
+ * @return int The count of records returned from the specified criteria.
+ */
+function count_records_select($table, $select='', $countitem='COUNT(*)') {
+
+    global $CFG;
+
+    if ($select) {
+        $select = 'WHERE '.$select;
+    }
+
+    return count_records_sql('SELECT '. $countitem .' FROM '. $CFG->prefix . $table .' '. $select);
+}
+
+/**
+ * Get the result of a SQL SELECT COUNT(...) query.
+ *
+ * Given a query that counts rows, return that count. (In fact,
+ * given any query, return the first field of the first record
+ * returned. However, this method should only be used for the
+ * intended purpose.) If an error occurrs, 0 is returned.
+ *
+ * @uses $CFG
+ * @uses $db
+ * @param string $sql The SQL string you wish to be executed.
+ * @return int the count. If an error occurrs, 0 is returned.
+ */
+function count_records_sql($sql) {
+    $rs = get_recordset_sql($sql);
+
+    if (is_object($rs) and is_array($rs->fields)) {
+        return reset($rs->fields);
+    } else {
+        return 0;
+    }
+}
+
+/// GENERIC FUNCTIONS TO GET, INSERT, OR UPDATE DATA  ///////////////////////////////////
+
+
+/**
+ * Get a single record as an object using an SQL statement
+ *
+ * The SQL statement should normally only return one record. In debug mode
+ * you will get a warning if more record is returned (unless you
+ * set $expectmultiple to true). In non-debug mode, it just returns
+ * the first record.
+ *
+ * @uses $CFG
+ * @uses $db
+ * @param string $sql The SQL string you wish to be executed, should normally only return one record.
+ * @param bool $expectmultiple If the SQL cannot be written to conveniently return just one record,
+ *      set this to true to hide the debug message.
+ * @param bool $nolimit sometimes appending ' LIMIT 1' to the SQL causes an error. Set this to true
+ *      to stop your SQL being modified. This argument should probably be deprecated.
+ * @return Found record as object. False if not found or error
+ */
+function get_record_sql($sql, $expectmultiple=false, $nolimit=false) {
+
+    global $CFG;
+
+/// Default situation
+    $limitfrom = 0; /// Number of records to skip
+    $limitnum  = 1; /// Number of records to retrieve
+
+/// Only a few uses of the 2nd and 3rd parameter have been found
+/// I think that we should avoid to use them completely, one
+/// record is one record, and everything else should return error.
+/// So the proposal is to change all the uses, (4-5 inside Moodle
+/// Core), drop them from the definition and delete the next two
+/// "if" sentences. (eloy, 2006-08-19)
+
+    if ($nolimit) {
+        $limitfrom = 0;
+        $limitnum  = 0;
+    } else if ($expectmultiple) {
+        $limitfrom = 0;
+        $limitnum  = 1;
+    } else if (debugging('', DEBUG_DEVELOPER)) {
+        // Debugging mode - don't use a limit of 1, but do change the SQL, because sometimes that
+        // causes errors, and in non-debug mode you don't see the error message and it is
+        // impossible to know what's wrong.
+        $limitfrom = 0;
+        $limitnum  = 100;
+    }
+
+    if (!$rs = get_recordset_sql($sql, $limitfrom, $limitnum)) {
+        return false;
+    }
+
+    $recordcount = $rs->RecordCount();
+
+    if ($recordcount == 0) {          // Found no records
+        return false;
+
+    } else if ($recordcount == 1) {    // Found one record
+    /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
+    /// to '' (empty string) for Oracle. It's the only way to work with
+    /// all those NOT NULL DEFAULT '' fields until we definitively delete them
+        if ($CFG->dbfamily == 'oracle') {
+            array_walk($rs->fields, 'onespace2empty');
+        }
+    /// End of DIRTY HACK
+        return (object)$rs->fields;
+
+    } else {                          // Error: found more than one record
+        notify('Error:  Turn off debugging to hide this error.');
+        notify($sql . '(with limits ' . $limitfrom . ', ' . $limitnum . ')');
+        if ($records = $rs->GetAssoc(true)) {
+            notify('Found more than one record in get_record_sql !');
+            print_object($records);
+        } else {
+            notify('Very strange error in get_record_sql !');
+            print_object($rs);
+        }
+        print_continue("$CFG->wwwroot/$CFG->admin/config.php");
+    }
+}
+
+/**
+ * Gets one record from a table, as an object
+ *
+ * @uses $CFG
+ * @param string $table The database table to be checked against.
+ * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+ * @param string $fields A comma separated list of fields to be returned from the chosen table.
+ * @return object|false Returns an array of found records (as objects) or false if no records or error occured.
+ */
+function get_record_select($table, $select='', $fields='*') {
+
+    global $CFG;
+
+    if ($select) {
+        $select = 'WHERE '. $select;
+    }
+
+    return get_record_sql('SELECT '. $fields .' FROM '. $CFG->prefix . $table .' '. $select);
+}
+
+/**
+ * Get a number of records as an ADODB RecordSet.
+ *
+ * Selects records from the table $table.
+ *
+ * If specified, only records where the field $field has value $value are retured.
+ *
+ * If specified, the results will be sorted as specified by $sort. This
+ * is added to the SQL as "ORDER BY $sort". Example values of $sort
+ * mightbe "time ASC" or "time DESC".
+ *
+ * If $fields is specified, only those fields are returned.
+ *
+ * Since this method is a little less readable, use of it should be restricted to
+ * code where it's possible there might be large datasets being returned.  For known
+ * small datasets use get_records - it leads to simpler code.
+ *
+ * If you only want some of the records, specify $limitfrom and $limitnum.
+ * The query will skip the first $limitfrom records (according to the sort
+ * order) and then return the next $limitnum records. If either of $limitfrom
+ * or $limitnum is specified, both must be present.
+ *
+ * The return value is an ADODB RecordSet object
+ * @link http://phplens.com/adodb/reference.functions.adorecordset.html
+ * if the query succeeds. If an error occurrs, false is returned.
+ *
+ * @param string $table the table to query.
+ * @param string $field a field to check (optional).
+ * @param string $value the value the field must have (requred if field1 is given, else optional).
+ * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+ * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
+ * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+ * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+ * @return mixed an ADODB RecordSet object, or false if an error occured.
+ */
+function get_recordset($table, $field='', $value='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+
+    if ($field) {
+        $select = "$field = '$value'";
+    } else {
+        $select = '';
+    }
+
+    return get_recordset_select($table, $select, $sort, $fields, $limitfrom, $limitnum);
+}
+
+/**
+ * Get a number of records as an ADODB RecordSet.
+ *
+ * If given, $select is used as the SELECT parameter in the SQL query,
+ * otherwise all records from the table are returned.
+ *
+ * Other arguments and the return type as for @see function get_recordset.
+ *
+ * @uses $CFG
+ * @param string $table the table to query.
+ * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+ * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+ * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
+ * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+ * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+ * @return mixed an ADODB RecordSet object, or false if an error occured.
+ */
+function get_recordset_select($table, $select='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+
+    global $CFG;
+
+    if ($select) {
+        $select = ' WHERE '. $select;
+    }
+
+    if ($sort) {
+        $sort = ' ORDER BY '. $sort;
+    }
+
+    return get_recordset_sql('SELECT '. $fields .' FROM '. $CFG->prefix . $table . $select . $sort, $limitfrom, $limitnum);
+}
+
+/**
+ * Get a number of records as an ADODB RecordSet.
+ *
+ * Only records where $field takes one of the values $values are returned.
+ * $values should be a comma-separated list of values, for example "4,5,6,10"
+ * or "'foo','bar','baz'".
+ *
+ * Other arguments and the return type as for @see function get_recordset.
+ *
+ * @param string $table the table to query.
+ * @param string $field a field to check (optional).
+ * @param string $values comma separated list of values the field must have (requred if field is given, else optional).
+ * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+ * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
+ * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+ * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+ * @return mixed an ADODB RecordSet object, or false if an error occured.
+ */
+function get_recordset_list($table, $field='', $values='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+
+    if ($field) {
+        $select = "$field IN ($values)";
+    } else {
+        $select = '';
+    }
+
+    return get_recordset_select($table, $select, $sort, $fields, $limitfrom, $limitnum);
+}
+
+/**
+ * Get a number of records as an ADODB RecordSet.  $sql must be a complete SQL query.
+ * Since this method is a little less readable, use of it should be restricted to
+ * code where it's possible there might be large datasets being returned.  For known
+ * small datasets use get_records_sql - it leads to simpler code.
+ *
+ * The return type is as for @see function get_recordset.
+ *
+ * @uses $CFG
+ * @uses $db
+ * @param string $sql the SQL select query to execute.
+ * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+ * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+ * @return mixed an ADODB RecordSet object, or false if an error occured.
+ */
+function get_recordset_sql($sql, $limitfrom=null, $limitnum=null) {
+    global $CFG, $db;
+
+    if (empty($db)) {
+        return false;
+    }
+
+/// Temporary hack as part of phasing out all access to obsolete user tables  XXX
+    if (!empty($CFG->rolesactive)) {
+        if (strpos($sql, ' '.$CFG->prefix.'user_students ') ||
+            strpos($sql, ' '.$CFG->prefix.'user_teachers ') ||
+            strpos($sql, ' '.$CFG->prefix.'user_coursecreators ') ||
+            strpos($sql, ' '.$CFG->prefix.'user_admins ')) {
+            if (debugging()) { var_dump(debug_backtrace()); }
+            print_error('This SQL relies on obsolete tables!  Your code must be fixed by a developer.');
+        }
+    }
+
+
+    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+    if ($limitfrom || $limitnum) {
+        ///Special case, 0 must be -1 for ADOdb
+        $limitfrom = empty($limitfrom) ? -1 : $limitfrom;
+        $limitnum  = empty($limitnum) ? -1 : $limitnum;
+        $rs = $db->SelectLimit($sql, $limitnum, $limitfrom);
+    } else {
+        $rs = $db->Execute($sql);
+    }
+    if (!$rs) {
+        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
+        if (!empty($CFG->dblogerror)) {
+            $debug=array_shift(debug_backtrace());
+            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql with limits ($limitfrom, $limitnum)");
+        }
+        return false;
+    }
+
+    return $rs;
+}
+
+/**
+ * Utility function used by the following 4 methods. Note that for this to work, the first column
+ * in the recordset must contain unique values, as it is used as the key to the associative array.
+ *
+ * @param object an ADODB RecordSet object.
+ * @return mixed mixed an array of objects, or false if an error occured or the RecordSet was empty.
+ */
+function recordset_to_array($rs) {
+    global $CFG;
+
+    $debugging = debugging('', DEBUG_DEVELOPER);
+
+    if ($rs && !rs_EOF($rs)) {
+        $objects = array();
+    /// First of all, we are going to get the name of the first column
+    /// to introduce it back after transforming the recordset to assoc array
+    /// See http://docs.moodle.org/en/XMLDB_Problems, fetch mode problem.
+        $firstcolumn = $rs->FetchField(0);
+    /// Get the whole associative array
+        if ($records = $rs->GetAssoc(true)) {
+            foreach ($records as $key => $record) {
+            /// Really DIRTY HACK for Oracle, but it's the only way to make it work
+            /// until we got all those NOT NULL DEFAULT '' out from Moodle
+                if ($CFG->dbfamily == 'oracle') {
+                    array_walk($record, 'onespace2empty');
+                }
+            /// End of DIRTY HACK
+                $record[$firstcolumn->name] = $key;/// Re-add the assoc field
+                if ($debugging && array_key_exists($key, $objects)) {
+                    debugging("Did you remember to make the first column something unique in your call to get_records? Duplicate value '$key' found in column '".$firstcolumn->name."'.", DEBUG_DEVELOPER);
+                }
+                $objects[$key] = (object) $record; /// To object
+            }
+            return $objects;
+    /// Fallback in case we only have 1 field in the recordset. MDL-5877
+        } else if ($rs->_numOfFields == 1 && $records = $rs->GetRows()) {
+            foreach ($records as $key => $record) {
+            /// Really DIRTY HACK for Oracle, but it's the only way to make it work
+            /// until we got all those NOT NULL DEFAULT '' out from Moodle
+                if ($CFG->dbfamily == 'oracle') {
+                    array_walk($record, 'onespace2empty');
+                }
+            /// End of DIRTY HACK
+                if ($debugging && array_key_exists($record[$firstcolumn->name], $objects)) {
+                    debugging("Did you remember to make the first column something unique in your call to get_records? Duplicate value '".$record[$firstcolumn->name]."' found in column '".$firstcolumn->name."'.", DEBUG_DEVELOPER);
+                }
+                $objects[$record[$firstcolumn->name]] = (object) $record; /// The key is the first column value (like Assoc)
+            }
+            return $objects;
+        } else {
+            return false;
+        }
+    } else {
+        return false;
+    }
+}
+
+/**
+ * This function is used to get the current record from the recordset. It
+ * doesn't advance the recordset position. You'll need to do that by
+ * using the rs_next_record($recordset) function.
+ * @param ADORecordSet the recordset to fetch current record from
+ * @return ADOFetchObj the object containing the fetched information
+ */
+function rs_fetch_record(&$rs) {
+    global $CFG;
+
+    if (!$rs) {
+        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
+        return false;
+    }
+
+    $rec = $rs->FetchObj(); //Retrieve record as object without advance the pointer
+
+    if ($rs->EOF) { //FetchObj requires manual checking of EOF to detect if it's the last record
+        $rec = false;
+    } else {
+    /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
+    /// to '' (empty string) for Oracle. It's the only way to work with
+    /// all those NOT NULL DEFAULT '' fields until we definetively delete them
+        if ($CFG->dbfamily == 'oracle') {
+            $recarr = (array)$rec; /// Cast to array
+            array_walk($recarr, 'onespace2empty');
+            $rec = (object)$recarr;/// Cast back to object
+        }
+    /// End DIRTY HACK
+    }
+
+    return $rec;
+}
+
+/**
+ * This function is used to advance the pointer of the recordset
+ * to its next position/record.
+ * @param ADORecordSet the recordset to be moved to the next record
+ * @return boolean true if the movement was successful and false if not (end of recordset)
+ */
+function rs_next_record(&$rs) {
+    if (!$rs) {
+        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
+        return false;
+    }
+
+    return $rs->MoveNext(); //Move the pointer to the next record
+}
+
+/**
+ * This function is used to get the current record from the recordset. It
+ * does advance the recordset position.
+ * This is the prefered way to iterate over recordsets with code blocks like this:
+ *
+ * $rs = get_recordset('SELECT .....');
+ * while ($rec = rs_fetch_next_record($rs)) {
+ *     /// Perform actions with the $rec record here
+ * }
+ * rs_close($rs); /// Close the recordset if not used anymore. Saves memory (optional but recommended).
+ *
+ * @param ADORecordSet the recordset to fetch current record from
+ * @return mixed ADOFetchObj the object containing the fetched information or boolean false if no record (end of recordset)
+ */
+function rs_fetch_next_record(&$rs) {
+
+    global $CFG;
+
+    if (!$rs) {
+        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
+        return false;
+    }
+
+    $rec = false;
+    $recarr = $rs->FetchRow(); //Retrieve record as object without advance the pointer. It's quicker that FetchNextObj()
+
+    if ($recarr) {
+    /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
+    /// to '' (empty string) for Oracle. It's the only way to work with
+    /// all those NOT NULL DEFAULT '' fields until we definetively delete them
+        if ($CFG->dbfamily == 'oracle') {
+            array_walk($recarr, 'onespace2empty');
+        }
+    /// End DIRTY HACK
+    /// Cast array to object
+        $rec = (object)$recarr;
+    }
+
+    return $rec;
+}
+
+/**
+ * Returns true if no more records found
+ * @param ADORecordSet the recordset
+ * @return bool
+ */
+function rs_EOF($rs) {
+    if (!$rs) {
+        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
+        return true;
+    }
+    return $rs->EOF;
+}
+
+/**
+ * This function closes the recordset, freeing all the memory and associated resources.
+ * Note that, once closed, the recordset must not be used anymore along the request.
+ * Saves memory (optional but recommended).
+ * @param ADORecordSet the recordset to be closed
+ * @return void
+ */
+function rs_close(&$rs) {
+    if (!$rs) {
+        debugging('Incorrect $rs used!', DEBUG_DEVELOPER);
+        return;
+    }
+
+    $rs->Close();
+}
+
+/**
+ * Get a number of records as an array of objects.
+ *
+ * Return value as for @see function get_records.
+ *
+ * @param string $table the table to query.
+ * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+ * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+ * @param string $fields a comma separated list of fields to return
+ *   (optional, by default all fields are returned). The first field will be used as key for the
+ *   array so must be a unique field such as 'id'.
+ * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+ * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+ * @return mixed an array of objects, or false if no records were found or an error occured.
+ */
+function get_records_select($table, $select='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+    $rs = get_recordset_select($table, $select, $sort, $fields, $limitfrom, $limitnum);
+    return recordset_to_array($rs);
+}
+
+/**
+ * Get a number of records as an array of objects.
+ *
+ * Return value as for @see function get_records.
+ *
+ * @param string $table The database table to be checked against.
+ * @param string $field The field to search
+ * @param string $values Comma separated list of possible value
+ * @param string $sort Sort order (as valid SQL sort parameter)
+ * @param string $fields A comma separated list of fields to be returned from the chosen table. If specified,
+ *   the first field should be a unique one such as 'id' since it will be used as a key in the associative
+ *   array.
+ * @return mixed an array of objects, or false if no records were found or an error occured.
+ */
+function get_records_list($table, $field='', $values='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+    $rs = get_recordset_list($table, $field, $values, $sort, $fields, $limitfrom, $limitnum);
+    return recordset_to_array($rs);
+}
+
+/**
+ * Get a number of records as an array of objects.
+ *
+ * Return value as for @see function get_records.
+ *
+ * @param string $sql the SQL select query to execute. The first column of this SELECT statement
+ *   must be a unique value (usually the 'id' field), as it will be used as the key of the
+ *   returned array.
+ * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+ * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+ * @return mixed an array of objects, or false if no records were found or an error occured.
+ */
+function get_records_sql($sql, $limitfrom='', $limitnum='') {
+    $rs = get_recordset_sql($sql, $limitfrom, $limitnum);
+    return recordset_to_array($rs);
+}
+
+/**
+ * Utility function used by the following 3 methods.
+ *
+ * @param object an ADODB RecordSet object with two columns.
+ * @return mixed an associative array, or false if an error occured or the RecordSet was empty.
+ */
+function recordset_to_menu($rs) {
+    global $CFG;
+    $menu = array();
+    if ($rs && !rs_EOF($rs)) {
+        $keys = array_keys($rs->fields);
+        $key0=$keys[0];
+        $key1=$keys[1];
+        while (!$rs->EOF) {
+            $menu[$rs->fields[$key0]] = $rs->fields[$key1];
+            $rs->MoveNext();
+        }
+        /// Really DIRTY HACK for Oracle, but it's the only way to make it work
+        /// until we got all those NOT NULL DEFAULT '' out from Moodle
+        if ($CFG->dbfamily == 'oracle') {
+            array_walk($menu, 'onespace2empty');
+        }
+        /// End of DIRTY HACK
+        return $menu;
+    } else {
+        return false;
+    }
+}
+
+/**
+ * Utility function
+ * Similar to recordset_to_menu
+ *
+ * field1, field2 is needed because the order from get_records_sql is not reliable
+ * @param records - records from get_records_sql() or get_records()
+ * @param field1 - field to be used as menu index
+ * @param field2 - feild to be used as coresponding menu value
+ * @return mixed an associative array, or false if an error occured or the RecordSet was empty.
+ */
+function records_to_menu($records, $field1, $field2) {
+
+    $menu = array();
+    foreach ($records as $record) {
+        $menu[$record->$field1] = $record->$field2;
+    }
+
+    if (!empty($menu)) {
+        return $menu;
+    } else {
+        return false;
+    }
+}
+
+/**
+ * Get the first two columns from a number of records as an associative array.
+ *
+ * Arguments as for @see function get_recordset.
+ *
+ * If no errors occur, and at least one records is found, the return value
+ * is an associative whose keys come from the first field of each record,
+ * and whose values are the corresponding second fields. If no records are found,
+ * or an error occurs, false is returned.
+ *
+ * @param string $table the table to query.
+ * @param string $field a field to check (optional).
+ * @param string $value the value the field must have (requred if field1 is given, else optional).
+ * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+ * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
+ * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+ * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+ * @return mixed an associative array, or false if no records were found or an error occured.
+ */
+function get_records_menu($table, $field='', $value='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+    $rs = get_recordset($table, $field, $value, $sort, $fields, $limitfrom, $limitnum);
+    return recordset_to_menu($rs);
+}
+
+/**
+ * Get the first two columns from a number of records as an associative array.
+ *
+ * Arguments as for @see function get_recordset_select.
+ * Return value as for @see function get_records_menu.
+ *
+ * @param string $table The database table to be checked against.
+ * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+ * @param string $sort Sort order (optional) - a valid SQL order parameter
+ * @param string $fields A comma separated list of fields to be returned from the chosen table.
+ * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+ * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+ * @return mixed an associative array, or false if no records were found or an error occured.
+ */
+function get_records_select_menu($table, $select='', $sort='', $fields='*', $limitfrom='', $limitnum='') {
+    $rs = get_recordset_select($table, $select, $sort, $fields, $limitfrom, $limitnum);
+    return recordset_to_menu($rs);
+}
+
+/**
+ * Get the first two columns from a number of records as an associative array.
+ *
+ * Arguments as for @see function get_recordset_sql.
+ * Return value as for @see function get_records_menu.
+ *
+ * @param string $sql The SQL string you wish to be executed.
+ * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+ * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+ * @return mixed an associative array, or false if no records were found or an error occured.
+ */
+function get_records_sql_menu($sql, $limitfrom='', $limitnum='') {
+    $rs = get_recordset_sql($sql, $limitfrom, $limitnum);
+    return recordset_to_menu($rs);
+}
+
+/**
+ * Get a single value from a table row where a particular select clause is true.
+ *
+ * @uses $CFG
+ * @param string $table the table to query.
+ * @param string $return the field to return the value of.
+ * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+ * @return mixed the specified value, or false if an error occured.
+ */
+function get_field_select($table, $return, $select) {
+    global $CFG;
+    if ($select) {
+        $select = 'WHERE '. $select;
+    }
+    return get_field_sql('SELECT ' . $return . ' FROM ' . $CFG->prefix . $table . ' ' . $select);
+}
+
+/**
+ * Get a single value from a table.
+ *
+ * @param string $sql an SQL statement expected to return a single value.
+ * @return mixed the specified value, or false if an error occured.
+ */
+function get_field_sql($sql) {
+    global $CFG;
+
+/// Strip potential LIMIT uses arriving here, debugging them (MDL-7173)
+    $newsql = preg_replace('/ LIMIT [0-9, ]+$/is', '', $sql);
+    if ($newsql != $sql) {
+        debugging('Incorrect use of LIMIT clause (not cross-db) in call to get_field_sql(): ' . s($sql), DEBUG_DEVELOPER);
+        $sql = $newsql;
+    }
+
+    $rs = get_recordset_sql($sql, 0, 1);
+
+    if ($rs && $rs->RecordCount() == 1) {
+        /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
+        /// to '' (empty string) for Oracle. It's the only way to work with
+        /// all those NOT NULL DEFAULT '' fields until we definetively delete them
+        if ($CFG->dbfamily == 'oracle') {
+            $value = reset($rs->fields);
+            onespace2empty($value);
+            return $value;
+        }
+        /// End of DIRTY HACK
+        return reset($rs->fields);
+    } else {
+        return false;
+    }
+}
+
+/**
+ * Get a single value from a table row where a particular select clause is true.
+ *
+ * @uses $CFG
+ * @param string $table the table to query.
+ * @param string $return the field to return the value of.
+ * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+ * @return mixed|false Returns the value return from the SQL statment or false if an error occured.
+ */
+function get_fieldset_select($table, $return, $select) {
+    global $CFG;
+    if ($select) {
+        $select = ' WHERE '. $select;
+    }
+    return get_fieldset_sql('SELECT ' . $return . ' FROM ' . $CFG->prefix . $table . $select);
+}
+
+/**
+ * Get an array of data from one or more fields from a database
+ * use to get a column, or a series of distinct values
+ *
+ * @uses $CFG
+ * @uses $db
+ * @param string $sql The SQL string you wish to be executed.
+ * @return mixed|false Returns the value return from the SQL statment or false if an error occured.
+ * @todo Finish documenting this function
+ */
+function get_fieldset_sql($sql) {
+
+    global $db, $CFG;
+
+    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+    $rs = $db->Execute($sql);
+    if (!$rs) {
+        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
+        if (!empty($CFG->dblogerror)) {
+            $debug=array_shift(debug_backtrace());
+            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql");
+        }
+        return false;
+    }
+
+    if ( !rs_EOF($rs) ) {
+        $keys = array_keys($rs->fields);
+        $key0 = $keys[0];
+        $results = array();
+        while (!$rs->EOF) {
+            array_push($results, $rs->fields[$key0]);
+            $rs->MoveNext();
+        }
+        /// DIRTY HACK to retrieve all the ' ' (1 space) fields converted back
+        /// to '' (empty string) for Oracle. It's the only way to work with
+        /// all those NOT NULL DEFAULT '' fields until we definetively delete them
+        if ($CFG->dbfamily == 'oracle') {
+            array_walk($results, 'onespace2empty');
+        }
+        /// End of DIRTY HACK
+        rs_close($rs);
+        return $results;
+    } else {
+        rs_close($rs);
+        return false;
+    }
+}
+
+/**
+ * Set a single field in every table row where the select statement evaluates to true.
+ *
+ * @uses $CFG
+ * @uses $db
+ * @param string $table The database table to be checked against.
+ * @param string $newfield the field to set.
+ * @param string $newvalue the value to set the field to.
+ * @param string $select a fragment of SQL to be used in a where clause in the SQL call.
+ * @param boolean $localcall Leave this set to false. (Should only be set to true by set_field.)
+ * @return mixed An ADODB RecordSet object with the results from the SQL call or false.
+ */
+function set_field_select($table, $newfield, $newvalue, $select, $localcall = false) {
+
+    global $db, $CFG;
+
+    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+    if (!$localcall) {
+        if ($select) {
+            $select = 'WHERE ' . $select;
+        }
+    }
+
+    $dataobject = new StdClass;
+    $dataobject->{$newfield} = $newvalue;
+    // Oracle DIRTY HACK -
+    if ($CFG->dbfamily == 'oracle') {
+        oracle_dirty_hack($table, $dataobject); // Convert object to the correct "empty" values for Oracle DB
+        $newvalue = $dataobject->{$newfield};
+    }
+    // End DIRTY HACK
+
+/// Under Oracle, MSSQL and PostgreSQL we have our own set field process
+/// If the field being updated is clob/blob, we use our alternate update here
+/// They will be updated later
+    if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') && !empty($select)) {
+    /// Detect lobs
+        $foundclobs = array();
+        $foundblobs = array();
+        db_detect_lobs($table, $dataobject, $foundclobs, $foundblobs);
+    }
+
+/// Under Oracle, MSSQL and PostgreSQL, finally, update all the Clobs and Blobs present in the record
+/// if we know we have some of them in the query
+    if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') && !empty($select) &&
+      (!empty($foundclobs) || !empty($foundblobs))) {
+        if (!db_update_lobs($table, $select, $foundclobs, $foundblobs)) {
+            return false; //Some error happened while updating LOBs
+        } else {
+            return true; //Everrything was ok
+        }
+    }
+
+/// NULL inserts - introduced in 1.9
+    if (is_null($newvalue)) {
+        $update = "$newfield = NULL";
+    } else {
+        $update = "$newfield = '$newvalue'";
+    }
+
+/// Arriving here, standard update
+    $sql = 'UPDATE '. $CFG->prefix . $table .' SET '.$update.' '.$select;
+    $rs = $db->Execute($sql);
+    if (!$rs) {
+        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
+        if (!empty($CFG->dblogerror)) {
+            $debug=array_shift(debug_backtrace());
+            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql");
+        }
+        return false;
+    }
+    return $rs;
+}
+
+/**
+ * Delete one or more records from a table
+ *
+ * @uses $CFG
+ * @uses $db
+ * @param string $table The database table to be checked against.
+ * @param string $select A fragment of SQL to be used in a where clause in the SQL call (used to define the selection criteria).
+ * @return object A PHP standard object with the results from the SQL call.
+ * @todo Verify return type.
+ */
+function delete_records_select($table, $select='') {
+
+    global $CFG, $db;
+
+    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+    if ($select) {
+        $select = 'WHERE '.$select;
+    }
+
+    $sql = 'DELETE FROM '. $CFG->prefix . $table .' '. $select;
+    $rs = $db->Execute($sql);
+    if (!$rs) {
+        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
+        if (!empty($CFG->dblogerror)) {
+            $debug=array_shift(debug_backtrace());
+            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql");
+        }
+        return false;
+    }
+    return $rs;
+}
+
+/**
+ * Get the data type of a table column, using an ADOdb MetaType() call.
+ *
+ * @uses $CFG
+ * @uses $db
+ * @param string $table The name of the database table
+ * @param string $column The name of the field in the table
+ * @return string Field type or false if error
+ */
+
+function column_type($table, $column) {
+    global $CFG, $db;
+
+    if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+    $sql = 'SELECT '.$column.' FROM '.$CFG->prefix.$table.' WHERE 1=2';
+    if(!$rs = $db->Execute($sql)) {
+        debugging($db->ErrorMsg() .'<br /><br />'. s($sql));
+        if (!empty($CFG->dblogerror)) {
+            $debug=array_shift(debug_backtrace());
+            error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $sql");
+        }
+        return false;
+    }
+
+    $field = $rs->FetchField(0);
+    return $rs->MetaType($field->type);
+}
+
+/**
+ * This function will handle all the records before being inserted/updated to DB for Oracle
+ * installations. This is because the "special feature" of Oracle where the empty string is
+ * equal to NULL and this presents a problem with all our currently NOT NULL default '' fields.
+ *
+ * Once Moodle DB will be free of this sort of false NOT NULLS, this hack could be removed safely
+ *
+ * Note that this function is 100% private and should be used, exclusively by DML functions
+ * in this file. Also, this is considered a DIRTY HACK to be removed when possible. (stronk7)
+ *
+ * This function is private and must not be used outside dmllib at all
+ *
+ * @param $table string the table where the record is going to be inserted/updated (without prefix)
+ * @param $dataobject object the object to be inserted/updated
+ * @param $usecache boolean flag to determinate if we must use the per request cache of metadata
+ *        true to use it, false to ignore and delete it
+ */
+function oracle_dirty_hack ($table, &$dataobject, $usecache = true) {
+
+    global $CFG, $db, $metadata_cache;
+
+/// Init and delete metadata cache
+    if (!isset($metadata_cache) || !$usecache) {
+        $metadata_cache = array();
+    }
+
+/// For Oracle DB, empty strings are converted to NULLs in DB
+/// and this breaks a lot of NOT NULL columns currenty Moodle. In the future it's
+/// planned to move some of them to NULL, if they must accept empty values and this
+/// piece of code will become less and less used. But, for now, we need it.
+/// What we are going to do is to examine all the data being inserted and if it's
+/// an empty string (NULL for Oracle) and the field is defined as NOT NULL, we'll modify
+/// such data in the best form possible ("0" for booleans and numbers and " " for the
+/// rest of strings. It isn't optimal, but the only way to do so.
+/// In the oppsite, when retrieving records from Oracle, we'll decode " " back to
+/// empty strings to allow everything to work properly. DIRTY HACK.
+
+/// If the db isn't Oracle, return without modif
+    if ( $CFG->dbfamily != 'oracle') {
+        return;
+    }
+
+/// Get Meta info to know what to change, using the cached meta if exists
+    if (!isset($metadata_cache[$table])) {
+        $metadata_cache[$table] = array_change_key_case($db->MetaColumns($CFG->prefix . $table), CASE_LOWER);
+    }
+    $columns = $metadata_cache[$table];
+/// Iterate over all the fields in the insert, transforming values
+/// in the best possible form
+    foreach ($dataobject as $fieldname => $fieldvalue) {
+    /// If the field doesn't exist in metadata, skip
+        if (!isset($columns[strtolower($fieldname)])) {
+            continue;
+        }
+    /// If the field ins't VARCHAR or CLOB, skip
+        if ($columns[strtolower($fieldname)]->type != 'VARCHAR2' && $columns[strtolower($fieldname)]->type != 'CLOB') {
+            continue;
+        }
+    /// If the field isn't NOT NULL, skip (it's nullable, so accept empty values)
+        if (!$columns[strtolower($fieldname)]->not_null) {
+            continue;
+        }
+    /// If the value isn't empty, skip
+        if (!empty($fieldvalue)) {
+            continue;
+        }
+    /// Now, we have one empty value, going to be inserted to one NOT NULL, VARCHAR2 or CLOB field
+    /// Try to get the best value to be inserted
+
+    /// The '0' string doesn't need any transformation, skip
+        if ($fieldvalue === '0') {
+            continue;
+        }
+
+    /// Transformations start
+        if (gettype($fieldvalue) == 'boolean') {
+            $dataobject->$fieldname = '0'; /// Transform false to '0' that evaluates the same for PHP
+        } else if (gettype($fieldvalue) == 'integer') {
+            $dataobject->$fieldname = '0'; /// Transform 0 to '0' that evaluates the same for PHP
+        } else if (gettype($fieldvalue) == 'NULL') {
+            $dataobject->$fieldname = '0'; /// Transform NULL to '0' that evaluates the same for PHP
+        } else if ($fieldvalue === '') {
+            $dataobject->$fieldname = ' '; /// Transform '' to ' ' that DONT'T EVALUATE THE SAME
+                                           /// (we'll transform back again on get_records_XXX functions and others)!!
+        }
+    }
+}
+/// End of DIRTY HACK
+
+/**
+ * This function will search for all the CLOBs and BLOBs fields passed in the dataobject, replacing
+ * their contents by the fixed strings '@#CLOB#@' and '@#BLOB#@' and returning one array for all the
+ * found CLOBS and another for all the found BLOBS
+ * Used by Oracle drivers to perform the two-step insertion/update of LOBs and
+ * by MSSQL to perform the same exclusively for BLOBs (IMAGE fields)
+ *
+ * This function is private and must not be used outside dmllib at all
+ *
+ * @param $table string the table where the record is going to be inserted/updated (without prefix)
+ * @param $dataobject object the object to be inserted/updated
+ * @param $clobs array of clobs detected
+ * @param $dataobject array of blobs detected
+ * @param $unset boolean to specify if we must unset found LOBs from the original object (true) or
+ *        just return them modified to @#CLOB#@ and @#BLOB#@ (false)
+ * @param $usecache boolean flag to determinate if we must use the per request cache of metadata
+ *        true to use it, false to ignore and delete it
+ */
+function db_detect_lobs ($table, &$dataobject, &$clobs, &$blobs, $unset = false, $usecache = true) {
+
+error('todo');
+    global $CFG, $db, $metadata_cache;
+
+    $dataarray = (array)$dataobject; //Convert to array. It's supposed that PHP 4.3 doesn't iterate over objects
+
+/// Initial configuration, based on DB
+    switch ($CFG->dbfamily) {
+        case 'oracle':
+            $clobdbtype = 'CLOB'; //Name of clobs for this DB
+            $blobdbtype = 'BLOB'; //Name of blobs for this DB
+            break;
+        case 'mssql':
+            $clobdbtype = 'NOTPROCESSES'; //Name of clobs for this DB (under mssql flavours we don't process CLOBS)
+            $blobdbtype = 'IMAGE'; //Name of blobs for this DB
+            break;
+        case 'postgres':
+            $clobdbtype = 'NOTPROCESSES'; //Name of clobs for this DB (under postgres flavours we don't process CLOBS)
+            $blobdbtype = 'BYTEA'; //Name of blobs for this DB
+            break;
+        default:
+            return; //Other DB doesn't need this two step to happen, prevent continue
+    }
+
+/// Init and delete metadata cache
+    if (!isset($metadata_cache) || !$usecache) {
+        $metadata_cache = array();
+    }
+
+/// Get Meta info to know what to change, using the cached meta if exists
+    if (!isset($metadata_cache[$table])) {
+        $metadata_cache[$table] = array_change_key_case($db->MetaColumns($CFG->prefix . $table), CASE_LOWER);
+    }
+    $columns = $metadata_cache[$table];
+
+    foreach ($dataarray as $fieldname => $fieldvalue) {
+    /// If the field doesn't exist in metadata, skip
+        if (!isset($columns[strtolower($fieldname)])) {
+            continue;
+        }
+    /// If the field is CLOB, update its value to '@#CLOB#@' and store it in the $clobs array
+        if (strtoupper($columns[strtolower($fieldname)]->type) == $clobdbtype) {
+        /// Oracle optimization. CLOBs under 4000cc can be directly inserted (no need to apply 2-phases to them)
+            if ($CFG->dbfamily == 'oracle' && strlen($dataobject->$fieldname) < 4000) {
+                continue;
+            }
+            $clobs[$fieldname] = $dataobject->$fieldname;
+            if ($unset) {
+                unset($dataobject->$fieldname);
+            } else {
+                $dataobject->$fieldname = '@#CLOB#@';
+            }
+            continue;
+        }
+
+    /// If the field is BLOB OR IMAGE OR BYTEA, update its value to '@#BLOB#@' and store it in the $blobs array
+        if (strtoupper($columns[strtolower($fieldname)]->type) == $blobdbtype) {
+            $blobs[$fieldname] = $dataobject->$fieldname;
+            if ($unset) {
+                unset($dataobject->$fieldname);
+            } else {
+                $dataobject->$fieldname = '@#BLOB#@';
+            }
+            continue;
+        }
+    }
+}
+
+/**
+ * This function will iterate over $clobs and $blobs array, executing the needed
+ * UpdateClob() and UpdateBlob() ADOdb function calls to store LOBs contents properly
+ * Records to be updated are always searched by PK (id always!)
+ *
+ * Used by Orace CLOBS and BLOBS and MSSQL IMAGES
+ *
+ * This function is private and must not be used outside dmllib at all
+ *
+ * @param $table string the table where the record is going to be inserted/updated (without prefix)
+ * @param $sqlcondition mixed value defining the records to be LOB-updated. It it's a number, must point
+ *        to the PK og the table (id field), else it's processed as one harcoded SQL condition (WHERE clause)
+ * @param $clobs array of clobs to be updated
+ * @param $blobs array of blobs to be updated
+ */
+function db_update_lobs ($table, $sqlcondition, &$clobs, &$blobs) {
+
+error('todo');
+
+    global $CFG, $db;
+
+    $status = true;
+
+/// Initial configuration, based on DB
+    switch ($CFG->dbfamily) {
+        case 'oracle':
+            $clobdbtype = 'CLOB'; //Name of clobs for this DB
+            $blobdbtype = 'BLOB'; //Name of blobs for this DB
+            break;
+        case 'mssql':
+            $clobdbtype = 'NOTPROCESSES'; //Name of clobs for this DB (under mssql flavours we don't process CLOBS)
+            $blobdbtype = 'IMAGE'; //Name of blobs for this DB
+            break;
+        case 'postgres':
+            $clobdbtype = 'NOTPROCESSES'; //Name of clobs for this DB (under postgres flavours we don't process CLOBS)
+            $blobdbtype = 'BYTEA'; //Name of blobs for this DB
+            break;
+        default:
+            return; //Other DB doesn't need this two step to happen, prevent continue
+    }
+
+/// Calculate the update sql condition
+    if (is_numeric($sqlcondition)) { /// If passing a number, it's the PK of the table (id)
+        $sqlcondition = 'id=' . $sqlcondition;
+    } else { /// Else, it's a formal standard SQL condition, we try to delete the WHERE in case it exists
+        $sqlcondition = trim(preg_replace('/^WHERE/is', '', trim($sqlcondition)));
+    }
+
+/// Update all the clobs
+    if ($clobs) {
+        foreach ($clobs as $key => $value) {
+
+            if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; }; /// Count the extra updates in PERF
+
+        /// Oracle CLOBs doesn't like quoted strings (are inserted via prepared statemets)
+            if ($CFG->dbfamily == 'oracle') {
+                $value = stripslashes_safe($value);
+            }
+
+            if (!$db->UpdateClob($CFG->prefix.$table, $key, $value, $sqlcondition)) {
+                $status = false;
+                $statement = "UpdateClob('$CFG->prefix$table', '$key', '" . substr($value, 0, 100) . "...', '$sqlcondition')";
+                debugging($db->ErrorMsg() ."<br /><br />".s($statement));
+                if (!empty($CFG->dblogerror)) {
+                    $debug=array_shift(debug_backtrace());
+                    error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $statement");
+                }
+            }
+        }
+    }
+/// Update all the blobs
+    if ($blobs) {
+        foreach ($blobs as $key => $value) {
+
+            if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; }; /// Count the extra updates in PERF
+
+        /// Oracle, MSSQL and PostgreSQL BLOBs doesn't like quoted strings (are inserted via prepared statemets)
+            if ($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') {
+                $value = stripslashes_safe($value);
+            }
+
+            if(!$db->UpdateBlob($CFG->prefix.$table, $key, $value, $sqlcondition)) {
+                $status = false;
+                $statement = "UpdateBlob('$CFG->prefix$table', '$key', '" . substr($value, 0, 100) . "...', '$sqlcondition')";
+                debugging($db->ErrorMsg() ."<br /><br />".s($statement));
+                if (!empty($CFG->dblogerror)) {
+                    $debug=array_shift(debug_backtrace());
+                    error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $statement");
+                }
+            }
+        }
+    }
+    return $status;
+}
+
+?>
Index: lib/xmldb/XMLDBObject.class.php
===================================================================
RCS file: lib/xmldb/XMLDBObject.class.php
diff -N lib/xmldb/XMLDBObject.class.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/xmldb/XMLDBObject.class.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,450 @@
+<?php // $Id: XMLDBObject.class.php,v 1.7 2007/10/10 05:25:14 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represent the XMLDB base class where all the common piezes
+/// are defined
+
+class XMLDBObject {
+
+    var $name;
+    var $comment;
+    var $previous;
+    var $next;
+    var $hash;
+    var $loaded;
+    var $changed;
+    var $errormsg;
+
+    /**
+     * Creates one new XMLDBObject
+     */
+    function XMLDBObject($name) {
+        $this->name = $name;
+        $this->comment = NULL;
+        $this->previous = NULL;
+        $this->next = NULL;
+        $this->hash = NULL;
+        $this->loaded = false;
+        $this->changed = false;
+        $this->errormsg = NULL;
+    }
+
+    /**
+     * This function returns true/false, if the XMLDBObject has been loaded
+     */
+    function isLoaded() {
+        return $this->loaded;
+    }
+
+    /**
+     * This function returns true/false, if the XMLDBObject has changed
+     */
+    function hasChanged() {
+        return $this->changed;
+    }
+
+    /**
+     * This function returns the comment of one XMLDBObject
+     */
+    function getComment() {
+        return $this->comment;
+    }
+
+    /**
+     * This function returns the hash of one XMLDBObject
+     */
+    function getHash() {
+        return $this->hash;
+    }
+
+    /**
+     * This function will return the name of the previous XMLDBObject
+     */
+    function getPrevious() {
+        return $this->previous;
+    }
+
+    /**
+     * This function will return the name of the next XMLDBObject
+     */
+    function getNext() {
+        return $this->next;
+    }
+
+    /**
+     * This function will return the name of the XMLDBObject
+     */
+    function getName() {
+        return $this->name;
+    }
+
+    /**
+     * This function will return the error detected in the object
+     */
+    function getError() {
+        return $this->errormsg;
+    }
+
+    /**
+     * This function will set the comment of the XMLDB object
+     */
+    function setComment($comment) {
+        $this->comment = $comment;
+    }
+
+    /**
+     * This function will set the previous of the XMLDB object
+     */
+    function setPrevious($previous) {
+        $this->previous = $previous;
+    }
+
+    /**
+     * This function will set the next of the XMLDB object
+     */
+    function setNext($next) {
+        $this->next = $next;
+    }
+
+    /**
+     * This function will set the hash of the XMLDB object
+     */
+    function setHash($hash) {
+        $this->hash = $hash;
+    }
+
+    /**
+     * This function will set the loaded field of the XMLDB object
+     */
+    function setLoaded($loaded = true) {
+        $this->loaded = $loaded;
+    }
+
+    /**
+     * This function will set the changed field of the XMLDB object
+     */
+    function setChanged($changed = true) {
+        $this->changed = $changed;
+    }
+    /**
+     * This function will set the name field of the XMLDB object
+     */
+    function setName($name) {
+        $this->name = $name;
+    }
+
+
+    /**
+     * This function will check if one key name is ok or no (true/false)
+     * only lowercase a-z, 0-9 and _ are allowed
+     */
+    function checkName () {
+        $result = true;
+
+        if ($this->name != eregi_replace('[^a-z0-9_ -]', '', $this->name)) {
+            $result = false;
+        }
+        return $result;
+    }
+
+    /**
+     * This function will check that all the elements in one array
+     * have a correct name [a-z0-9_]
+     */
+    function checkNameValues(&$arr) {
+        $result = true;
+    /// TODO: Perhaps, add support for reserved words
+
+    /// Check the name only contains valid chars
+        if ($arr) {
+            foreach($arr as $element) {
+                if (!$element->checkName()) {
+                    $result = false;
+                }
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Reconstruct previous/next attributes.
+     */
+    function fixPrevNext(&$arr) {
+        global $CFG;
+
+        if (empty($CFG->xmldbreconstructprevnext)) {
+            return false;
+        }
+        $tweaked = false;
+
+        $prev = null;
+        foreach ($arr as $key=>$el) {
+            $prev_value = $arr[$key]->previous;
+            $next_value = $arr[$key]->next;
+
+            $arr[$key]->next     = null;
+            $arr[$key]->previous = null;
+            if ($prev !== null) {
+                $arr[$prev]->next    = $arr[$key]->name;
+                $arr[$key]->previous = $arr[$prev]->name;
+            }
+            $prev = $key;
+
+            if ($prev_value != $arr[$key]->previous or $next_value != $arr[$key]->next) {
+                $tweaked = true;
+            }
+        }
+
+        return $tweaked;
+    }
+
+    /**
+     * This function will check that all the elements in one array
+     * have a consistent info in their previous/next fields
+     */
+    function checkPreviousNextValues(&$arr) {
+        global $CFG;
+        if (!empty($CFG->xmldbdisablenextprevchecking)) {
+            return true;
+        }
+        $result = true;
+    /// Check that only one element has the previous not set
+        if ($arr) {
+            $counter = 0;
+            foreach($arr as $element) {
+                if (!$element->getPrevious()) {
+                    $counter++;
+                }
+            }
+            if ($counter != 1) {
+                $result = false;
+            }
+        }
+    /// Check that only one element has the next not set
+        if ($result && $arr) {
+            $counter = 0;
+            foreach($arr as $element) {
+                if (!$element->getNext()) {
+                    $counter++;
+                }
+            }
+            if ($counter != 1) {
+                $result = false;
+            }
+        }
+    /// Check that all the previous elements are existing elements
+        if ($result && $arr) {
+            foreach($arr as $element) {
+                if ($element->getPrevious()) {
+                    $i = $this->findObjectInArray($element->getPrevious(), $arr);
+                    if ($i === NULL) {
+                        $result = false;
+                    }
+                }
+            }
+        }
+    /// Check that all the next elements are existing elements
+        if ($result && $arr) {
+            foreach($arr as $element) {
+                if ($element->getNext()) {
+                    $i = $this->findObjectInArray($element->getNext(), $arr);
+                    if ($i === NULL) {
+                        $result = false;
+                    }
+                }
+            }
+        }
+    /// Check that there aren't duplicates in the previous values
+        if ($result && $arr) {
+            $existarr = array();
+            foreach($arr as $element) {
+                if (in_array($element->getPrevious(), $existarr)) {
+                    $result = false;
+                } else {
+                    $existarr[] = $element->getPrevious();
+                }
+            }
+        }
+    /// Check that there aren't duplicates in the next values
+        if ($result && $arr) {
+            $existarr = array();
+            foreach($arr as $element) {
+                if (in_array($element->getNext(), $existarr)) {
+                    $result = false;
+                } else {
+                    $existarr[] = $element->getNext();
+                }
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * This function will order all the elements in one array, following
+     * the previous/next rules
+     */
+    function orderElements($arr) {
+        global $CFG;
+        $result = true;
+        if (!empty($CFG->xmldbdisablenextprevchecking)) {
+            return $arr;
+        }
+    /// Create a new array
+        $newarr = array();
+        if (!empty($arr)) {
+            $currentelement = NULL;
+        /// Get the element without previous
+            foreach($arr as $key => $element) {
+                if (!$element->getPrevious()) {
+                    $currentelement = $arr[$key];
+                    $newarr[0] = $arr[$key];
+                }
+            }
+            if (!$currentelement) {
+                $result = false;
+            }
+        /// Follow the next rules
+            $counter = 1;
+            while ($result && $currentelement->getNext()) {
+                $i = $this->findObjectInArray($currentelement->getNext(), $arr);
+                $currentelement = $arr[$i];
+                $newarr[$counter] = $arr[$i];
+                $counter++;
+            }
+        /// Compare number of elements between original and new array
+            if ($result && count($arr) != count($newarr)) {
+                $result = false;
+            }
+        /// Check that previous/next is ok (redundant but...)
+            if ($this->checkPreviousNextValues($newarr)) {
+                $result = $newarr;
+            } else {
+                $result = false;
+            }
+        } else {
+            $result = array();
+        }
+        return $result;
+    }
+
+    /**
+     * Returns the position of one object in the array.
+     */
+    function &findObjectInArray($objectname, $arr) {
+        foreach ($arr as $i => $object) {
+            if ($objectname == $object->getName()) {
+                return $i;
+            }
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * This function will display a readable info about the XMLDBObject
+     * (should be implemented inside each XMLDBxxx object)
+     */
+    function readableInfo() {
+        return get_class($this);
+    }
+
+    /**
+     * This function will perform the central debug of all the XMLDB classes
+     * being called automatically every time one error is found. Apart from 
+     * the main actions performed in it (XMLDB agnostic) it looks for one
+     * function called xmldb_debug() and invokes it, passing both the
+     * message code and the whole object. 
+     * So, to perform custom debugging just add such function to your libs.
+     * 
+     * Call to the external hook function can be disabled by request by
+     * defining XMLDB_SKIP_DEBUG_HOOK
+     */
+    function debug($message) {
+
+    /// Check for xmldb_debug($message, $xmldb_object)
+        $funcname = 'xmldb_debug';
+    /// If exists and XMLDB_SKIP_DEBUG_HOOK is undefined
+        if (function_exists($funcname) && !defined('XMLDB_SKIP_DEBUG_HOOK')) {
+            $funcname($message, $this);
+        }
+    }
+
+    /**
+     * Returns one array of elements from one comma separated string,
+     * supporting quoted strings containing commas and concat function calls
+     */
+    function comma2array($string) {
+
+        $arr = array();
+
+        $foundquotes  = array();
+        $foundconcats = array();
+
+    /// Extract all the concat elements from the string
+        preg_match_all("/(CONCAT\(.*?\))/is", $string, $matches);
+        foreach (array_unique($matches[0]) as $key=>$value) {
+            $foundconcats['<#'.$key.'#>'] = $value;
+        }
+        if (!empty($foundconcats)) {
+            $string = str_replace($foundconcats,array_keys($foundconcats),$string);
+        }
+
+    /// Extract all the quoted elements from the string (skipping 
+    /// backslashed quotes that are part of the content.
+        preg_match_all("/('.*?[^\\\]')/is", $string, $matches);
+        foreach (array_unique($matches[0]) as $key=>$value) {
+            $foundquotes['<%'.$key.'%>'] = $value;
+        }
+        if (!empty($foundquotes)) {
+            $string = str_replace($foundquotes,array_keys($foundquotes),$string);
+        }
+
+    /// Explode safely the string
+        $arr = explode (',', $string);
+
+    /// Put the concat and quoted elements back again, triming every element
+        if ($arr) {
+            foreach ($arr as $key => $element) {
+            /// Clear some spaces
+                $element = trim($element);
+            /// Replace the quoted elements if exists
+                if (!empty($foundquotes)) {
+                    $element = str_replace(array_keys($foundquotes), $foundquotes, $element);
+                }
+            /// Replace the concat elements if exists
+                if (!empty($foundconcats)) {
+                    $element = str_replace(array_keys($foundconcats), $foundconcats, $element);
+                }
+            /// Delete any backslash used for quotes. XMLDB stuff will add them before insert
+                $arr[$key] = str_replace("\\'", "'", $element);
+            }
+        }
+
+        return $arr;
+    }
+}
+
+?>
Index: lib/dml/adodb_moodle_recordset.php
===================================================================
RCS file: lib/dml/adodb_moodle_recordset.php
diff -N lib/dml/adodb_moodle_recordset.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/adodb_moodle_recordset.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * Adodb basic moodle recordset class
+ * @package dmlib
+ */
+class adodb_moodle_recordset implements moodle_recordset {
+    private $rs;
+
+    public function __construct($rs) {
+        $this->rs = $rs;
+    }
+
+    public function current() {
+        return (object)$this->rs->fields;
+    }
+
+    public function key() {
+        return $this->rs->_currentRow;
+    }
+
+    public function next() {
+        $this->rs->MoveNext();
+    }
+
+    public function rewind() {
+        $this->rs->MoveFirst();
+    }
+
+    public function valid() {
+        return !$this->rs->EOF;
+    }
+
+    public function close() {
+        $this->rs->Close();
+        $this->rs = null;
+    }
+}
Index: lib/dml/pdo_moodle_recordset.php
===================================================================
RCS file: lib/dml/pdo_moodle_recordset.php
diff -N lib/dml/pdo_moodle_recordset.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/pdo_moodle_recordset.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * Experimental pdo recordset
+ * @package dmlib
+ */
+class adodb_moodle_recordset implements moodle_recordset {
+    private $sht;
+
+    public function __construct($sth) {
+        $this->sth = $sth;
+    }
+
+    public function current() {
+        error('TODO');
+    }
+
+    public function key() {
+        error('TODO');
+    }
+
+    public function next() {
+        error('TODO');
+    }
+
+    public function rewind() {
+        error('TODO');
+    }
+
+    public function valid() {
+        error('TODO');
+    }
+
+    public function close() {
+        $this->sth->closeCursor();
+        $this->sth = null;
+    }
+}
Index: lib/ddl/mssql_sql_generator.php
===================================================================
RCS file: lib/ddl/mssql_sql_generator.php
diff -N lib/ddl/mssql_sql_generator.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/ddl/mssql_sql_generator.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,625 @@
+<?php // $Id: mssql.class.php,v 1.41 2007/10/10 05:25:18 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once($CFG->libdir.'/ddl/sql_generator.php');
+
+/// This class generate SQL code to be used against MSSQL
+/// It extends XMLDBgenerator so everything can be
+/// overriden as needed to generate correct SQL.
+
+class mssql_sql_generator extends sql_generator {
+
+/// Only set values that are different from the defaults present in XMLDBgenerator
+
+    public $statement_end = "\ngo"; // String to be automatically added at the end of each statement
+
+    public $number_type = 'DECIMAL';    // Proper type for NUMBER(x) in this DB
+
+    public $unsigned_allowed = false;    // To define in the generator must handle unsigned information
+    public $default_for_char = '';      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
+
+    public $specify_nulls = true;  //To force the generator if NULL clauses must be specified. It shouldn't be necessary
+                                     //but some mssql drivers require them or everything is created as NOT NULL :-(
+
+    public $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
+    public $sequence_name = 'IDENTITY(1,1)'; //Particular name for inline sequences in this generator
+    public $sequence_only = false; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable
+
+    public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
+
+    public $add_table_comments  = false;  // Does the generator need to add code for table comments
+
+    public $concat_character = '+'; //Characters to be used as concatenation operator. If not defined
+                                  //MySQL CONCAT function will be use
+
+    public $rename_table_sql = "sp_rename 'OLDNAME', 'NEWNAME'"; //SQL sentence to rename one table, both
+                                  //OLDNAME and NEWNAME are dinamically replaced
+
+    public $rename_column_sql = "sp_rename 'TABLENAME.OLDFIELDNAME', 'NEWFIELDNAME', 'COLUMN'";
+                                      ///TABLENAME, OLDFIELDNAME and NEWFIELDNAME are dianmically replaced
+
+    public $drop_index_sql = 'DROP INDEX TABLENAME.INDEXNAME'; //SQL sentence to drop one index
+                                                               //TABLENAME, INDEXNAME are dinamically replaced
+
+    public $rename_index_sql = "sp_rename 'TABLENAME.OLDINDEXNAME', 'NEWINDEXNAME', 'INDEX'"; //SQL sentence to rename one index
+                                      //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dinamically replaced
+
+    public $rename_key_sql = null; //SQL sentence to rename one key
+                                          //TABLENAME, OLDKEYNAME, NEWKEYNAME are dinamically replaced
+
+    /**
+     * Creates one new XMLDBmssql
+     */
+    public function __construct($mdb) {
+        parent::__construct($mdb);
+    }
+
+    /**
+     * This function will create the temporary table passed as argument with all its
+     * fields/keys/indexes/sequences, everything based in the XMLDB object
+     *
+     * TRUNCATE the table immediately after creation. A previous process using
+     * the same persistent connection may have created the temp table and failed to
+     * drop it. In that case, the table will exist, and create_temp_table() will
+     * will succeed.
+     *
+     * NOTE: The return value is the tablename - some DBs (MSSQL at least) use special
+     * names for temp tables.
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return string tablename on success, false on error
+     */
+    function create_temp_table($xmldb_table, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect create_table() $xmldb_table parameter');
+            return false;
+        }
+
+    /// Check table doesn't exist
+        if ($this->table_exists($xmldb_table)) {
+            debugging('Table ' . $xmldb_table->getName() .
+                      ' already exists. Create skipped', DEBUG_DEVELOPER);
+            return $xmldb_table->getName(); //Table exists, nothing to do
+        }
+
+        if (!$sqlarr = $this->getCreateTableSQL($xmldb_table)) {
+            return $xmldb_table->getName(); //Empty array = nothing to do = no error
+        }
+
+        // TODO: somehow change the name to have a #
+        /*$temporary = '';
+
+        if (!empty($temporary)) {
+            $sqlarr = preg_replace('/^CREATE/', "CREATE $temporary", $sqlarr);
+        }*/
+
+        if (execute_sql_arr($sqlarr, $continue, $feedback)) {
+            return $xmldb_table->getName();
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
+     */
+    public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
+
+        switch ($xmldb_type) {
+            case XMLDB_TYPE_INTEGER:    // From http://msdn.microsoft.com/library/en-us/tsqlref/ts_da-db_7msw.asp?frame=true
+                if (empty($xmldb_length)) {
+                    $xmldb_length = 10;
+                }
+                if ($xmldb_length > 9) {
+                    $dbtype = 'BIGINT';
+                } else if ($xmldb_length > 4) {
+                    $dbtype = 'INTEGER';
+                } else {
+                    $dbtype = 'SMALLINT';
+                }
+                break;
+            case XMLDB_TYPE_NUMBER:
+                $dbtype = $this->number_type;
+                if (!empty($xmldb_length)) {
+                /// 38 is the max allowed
+                    if ($xmldb_length > 38) {
+                        $xmldb_length = 38;
+                    }
+                    $dbtype .= '(' . $xmldb_length;
+                    if (!empty($xmldb_decimals)) {
+                        $dbtype .= ',' . $xmldb_decimals;
+                    }
+                    $dbtype .= ')';
+                }
+                break;
+            case XMLDB_TYPE_FLOAT:
+                $dbtype = 'FLOAT';
+                if (!empty($xmldb_decimals)) {
+                    if ($xmldb_decimals < 6) {
+                        $dbtype = 'REAL';
+                    }
+                }
+                break;
+            case XMLDB_TYPE_CHAR:
+                $dbtype = 'NVARCHAR';
+                if (empty($xmldb_length)) {
+                    $xmldb_length='255';
+                }
+                $dbtype .= '(' . $xmldb_length . ')';
+                break;
+            case XMLDB_TYPE_TEXT:
+                $dbtype = 'NTEXT';
+                break;
+            case XMLDB_TYPE_BINARY:
+                $dbtype = 'IMAGE';
+                break;
+            case XMLDB_TYPE_DATETIME:
+                $dbtype = 'DATETIME';
+                break;
+        }
+        return $dbtype;
+    }
+
+    /**
+     * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
+     */
+    public function getEnumExtraSQL($xmldb_table, $xmldb_field) {
+
+        $sql = 'CONSTRAINT ' . $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'ck');
+        $sql.= ' CHECK (' . $this->getEncQuoted($xmldb_field->getName()) . ' IN (' . implode(', ', $xmldb_field->getEnumValues()) . '))';
+
+        return $sql;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop the field from the table
+     * MSSQL overwrites the standard sentence because it needs to do some extra work dropping the default and
+     * check constraints
+     */
+    public function getDropFieldSQL($xmldb_table, $xmldb_field) {
+
+        global $db;
+
+        $results = array();
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// Look for any default constraint in this field and drop it
+        if ($defaultname = $this->getDefaultConstraintName($xmldb_table, $xmldb_field)) {
+            $results[] = 'ALTER TABLE ' . $tablename . ' DROP CONSTRAINT ' . $defaultname;
+        }
+
+    /// Look for any check constraint in this field and drop it
+        if ($drop_check = $this->getDropEnumSQL($xmldb_table, $xmldb_field)) {
+            $results = array_merge($results, $drop_check);
+        }
+
+    /// Build the standard alter table drop column
+        $results[] = 'ALTER TABLE ' . $tablename . ' DROP COLUMN ' . $fieldname;
+
+        return $results;
+    }
+
+    /**
+     * Given one correct XMLDBField and the new name, returns the SQL statements
+     * to rename it (inside one array)
+     * MSSQL is special, so we overload the function here. It needs to
+     * drop the constraints BEFORE renaming the field
+     */
+    public function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
+
+        $results = array();  //Array where all the sentences will be stored
+
+    /// Although this is checked in ddllib - rename_field() - double check
+    /// that we aren't trying to rename one "id" field. Although it could be
+    /// implemented (if adding the necessary code to rename sequences, defaults,
+    /// triggers... and so on under each getRenameFieldExtraSQL() function, it's
+    /// better to forbide it, mainly because this field is the default PK and
+    /// in the future, a lot of FKs can be pointing here. So, this field, more
+    /// or less, must be considered inmutable!
+        if ($xmldb_field->getName() == 'id') {
+            return array();
+        }
+
+    /// Drop the check constraint if exists
+        if ($xmldb_field->getEnum()) {
+            $results = array_merge($results, $this->getDropEnumSQL($xmldb_table, $xmldb_field));
+        }
+
+    /// Call to standard (parent) getRenameFieldSQL() function
+        $results = array_merge($results, parent::getRenameFieldSQL($xmldb_table, $xmldb_field, $newname));
+
+        return $results;
+    }
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on field rename
+     */
+    public function getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname) {
+
+        $results = array();
+
+    /// If the field is enum, drop and re-create the check constraint
+        if ($xmldb_field->getEnum()) {
+        /// Drop the current enum (not needed, it has been dropped before for msqql (in getRenameFieldSQL)
+            //$results = array_merge($results, $this->getDropEnumSQL($xmldb_table, $xmldb_field));
+        /// Change field name (over a clone to avoid some potential problems later)
+            $new_xmldb_field = clone($xmldb_field);
+            $new_xmldb_field->setName($newname);
+
+        /// Recreate the enum
+            $results = array_merge($results, $this->getCreateEnumSQL($xmldb_table, $new_xmldb_field));
+        }
+
+        return $results;
+    }
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on table rename
+     */
+    public function getRenameTableExtraSQL($xmldb_table, $newname) {
+
+        $results = array();
+
+        $newt = new XMLDBTable($newname); //Temporal table for name calculations
+
+        $oldtablename = $this->getTableName($xmldb_table);
+        $newtablename = $this->getTableName($newt);
+
+    /// Rename all the check constraints in the table
+        $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
+        $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
+
+        if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
+            foreach ($constraints as $constraint) {
+            /// Drop the old constraint
+                $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
+            /// Calculate the new constraint name
+                $newconstraintname = str_replace($oldconstraintprefix, $newconstraintprefix, $constraint->name);
+            /// Add the new constraint
+                $results[] = 'ALTER TABLE ' . $newtablename . ' ADD CONSTRAINT ' . $newconstraintname .
+                             ' CHECK ' . $constraint->description;
+            }
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table
+     */
+    public function getAlterFieldSQL($xmldb_table, $xmldb_field) {
+
+        $results = array(); /// To store all the needed SQL commands
+
+    /// Get the quoted name of the table and field
+        $tablename = $xmldb_table->getName();
+        $fieldname = $xmldb_field->getName();
+
+    /// Take a look to field metadata
+        $this->mdb->reset_columns($tablename);
+
+        $meta = $this->mdb->get_columns($tablename);
+        $metac = $meta[$fieldname];
+        $oldmetatype = $$metac->meta_type;
+
+        $oldlength = $metac->max_length;
+        $olddecimals = empty($metac->scale) ? null : $metac->scale;
+        $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
+        $olddefault = empty($metac->has_default) ? null : strtok($metac->default_value, ':');
+
+        $typechanged = true;  //By default, assume that the column type has changed
+        $lengthchanged = true;  //By default, assume that the column length has changed
+
+    /// Detect if we are changing the type of the column
+        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_NUMBER  && $oldmetatype == 'N') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_FLOAT   && $oldmetatype == 'F') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_CHAR    && $oldmetatype == 'C') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && $oldmetatype == 'X') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_BINARY  && $oldmetatype == 'B')) {
+            $typechanged = false;
+        }
+
+    /// Detect if we are changing the length of the column, not always necessary to drop defaults
+    /// if only the length changes, but it's safe to do it always
+        if ($xmldb_field->getLength() == $oldlength) {
+            $lengthchanged = false;
+        }
+
+    /// If type or length have changed drop the default if exists
+        if ($typechanged || $lengthchanged) {
+            $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field);
+        }
+
+    /// Just prevent default clauses in this type of sentences for mssql and launch the parent one
+        $this->alter_column_skip_default = true;
+        $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field)); // Call parent
+
+    /// Finally, process the default clause to add it back if necessary
+        if ($typechanged || $lengthchanged) {
+            $results = array_merge($results, $this->getCreateDefaultSQL($xmldb_table, $xmldb_field));
+        }
+
+    /// Return results
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to modify the default of the field in the table
+     */
+    public function getModifyDefaultSQL($xmldb_table, $xmldb_field) {
+    /// MSSQL is a bit special with default constraints because it implements them as external constraints so
+    /// normal ALTER TABLE ALTER COLUMN don't work to change defaults. Because this, we have this method overloaded here
+
+        $results = array();
+
+    /// Decide if we are going to create/modify or to drop the default
+        if ($xmldb_field->getDefault() === null) {
+            $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop but, under some circumptances, re-enable
+            $default_clause = $this->getDefaultClause($xmldb_field);
+            if ($default_clause) { //If getDefaultClause() it must have one default, create it
+                $results = array_merge($results, $this->getCreateDefaultSQL($xmldb_table, $xmldb_field)); //Create/modify
+            }
+        } else {
+            $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop (only if exists)
+            $results = array_merge($results, $this->getCreateDefaultSQL($xmldb_table, $xmldb_field)); //Create/modify
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public function getCreateEnumSQL($xmldb_table, $xmldb_field) {
+    /// All we have to do is to create the check constraint
+        return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
+                     ' ADD ' . $this->getEnumExtraSQL($xmldb_table, $xmldb_field));
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public function getDropEnumSQL($xmldb_table, $xmldb_field) {
+    /// Let's introspect to know the real name of the check constraint
+        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
+            $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
+            $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
+        /// All we have to do is to drop the check constraint
+            return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
+                     ' DROP CONSTRAINT ' . $constraint_name);
+        } else { /// Constraint not found. Nothing to do
+            return array();
+        }
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
+    /// MSSQL is a bit special and it requires the corresponding DEFAULT CONSTRAINT to be dropped
+
+        $results = array();
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// Now, check if, with the current field attributes, we have to build one default
+        $default_clause = $this->getDefaultClause($xmldb_field);
+        if ($default_clause) {
+        /// We need to build the default (Moodle) default, so do it
+            $sql = 'ALTER TABLE ' . $tablename . ' ADD' . $default_clause . ' FOR ' . $fieldname;
+            $results[] = $sql;
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
+    /// MSSQL is a bit special and it requires the corresponding DEFAULT CONSTRAINT to be dropped
+
+        $results = array();
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// Look for the default contraint and, if found, drop it
+        if ($defaultname = $this->getDefaultConstraintName($xmldb_table, $xmldb_field)) {
+            $results[] = 'ALTER TABLE ' . $tablename . ' DROP CONSTRAINT ' . $defaultname;
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, returns the name of its default constraint in DB
+     * or false if not found
+     * This function should be considered internal and never used outside from generator
+     */
+    public function getDefaultConstraintName($xmldb_table, $xmldb_field) {
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// Look for any default constraint in this field and drop it
+        if ($default = get_record_sql("SELECT id, object_name(cdefault) AS defaultconstraint
+                                         FROM syscolumns
+                                        WHERE id = object_id('{$tablename}')
+                                          AND name = '{$fieldname}'")) {
+            return $default->defaultconstraint;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Given one XMLDBTable returns one array with all the check constrainsts
+     * in the table (fetched from DB)
+     * Optionally the function allows one xmldb_field to be specified in
+     * order to return only the check constraints belonging to one field.
+     * Each element contains the name of the constraint and its description
+     * If no check constraints are found, returns an empty array
+     */
+    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
+
+        $results = array();
+
+        $tablename = $this->getTableName($xmldb_table);
+
+        if ($constraints = get_records_sql("SELECT o.name, c.text AS description
+                                            FROM sysobjects o,
+                                                 sysobjects p,
+                                                 syscomments c
+                                           WHERE p.id = o.parent_obj
+                                             AND o.id = c.id
+                                             AND o.xtype = 'C'
+                                             AND p.name = '{$tablename}'")) {
+            foreach ($constraints as $constraint) {
+                $results[$constraint->name] = $constraint;
+            }
+        }
+
+    /// Filter by the required field if specified
+        if ($xmldb_field) {
+            $filtered_results = array();
+            $filter = $xmldb_field->getName();
+        /// Lets clean a bit each constraint description, looking for the filtered field
+            foreach ($results as $key => $result) {
+                $description = trim(preg_replace('/[\(\)]/', '',  $result->description));   // Parenthesis out & trim
+                /// description starts by [$filter] assume it's a constraint beloging to the field
+                if (preg_match("/^\[{$filter}\]/i", $description)) {
+                    $filtered_results[$key] = $result;
+                }
+            }
+        /// Assign filtered results to the final results array
+            $results =  $filtered_results;
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
+     * return if such name is currently in use (true) or no (false)
+     * (invoked from getNameForObject()
+     */
+    public function isNameInUse($object_name, $type, $table_name) {
+        switch($type) {
+            case 'seq':
+            case 'trg':
+            case 'pk':
+            case 'uk':
+            case 'fk':
+            case 'ck':
+                if ($check = get_records_sql("SELECT name
+                                              FROM sysobjects
+                                              WHERE lower(name) = '" . strtolower($object_name) . "'")) {
+                    return true;
+                }
+                break;
+            case 'ix':
+            case 'uix':
+                if ($check = get_records_sql("SELECT name
+                                              FROM sysindexes
+                                              WHERE lower(name) = '" . strtolower($object_name) . "'")) {
+                    return true;
+                }
+                break;
+        }
+        return false; //No name in use found
+    }
+
+    /**
+     * Returns the code (in array) needed to add one comment to the table
+     */
+    public function getCommentSQL($xmldb_table) {
+        return array();
+    }
+
+    public function addslashes($s) {
+        // do not use php addslashes() because it depends on PHP quote settings!
+        $s = str_replace("'",  "''", $s);
+        return $s;
+    }
+
+    /**
+     * Returns an array of reserved words (lowercase) for this DB
+     */
+    public static function getReservedWords() {
+    /// This file contains the reserved words for MSSQL databases
+    /// from http://msdn2.microsoft.com/en-us/library/ms189822.aspx
+        $reserved_words = array (
+            'add', 'all', 'alter', 'and', 'any', 'as', 'asc', 'authorization',
+            'avg', 'backup', 'begin', 'between', 'break', 'browse', 'bulk',
+            'by', 'cascade', 'case', 'check', 'checkpoint', 'close', 'clustered',
+            'coalesce', 'collate', 'column', 'commit', 'committed', 'compute',
+            'confirm', 'constraint', 'contains', 'containstable', 'continue',
+            'controlrow', 'convert', 'count', 'create', 'cross', 'current',
+            'current_date', 'current_time', 'current_timestamp', 'current_user',
+            'cursor', 'database', 'dbcc', 'deallocate', 'declare', 'default', 'delete',
+            'deny', 'desc', 'disk', 'distinct', 'distributed', 'double', 'drop', 'dummy',
+            'dump', 'else', 'end', 'errlvl', 'errorexit', 'escape', 'except', 'exec',
+            'execute', 'exists', 'exit', 'external', 'fetch', 'file', 'fillfactor', 'floppy',
+            'for', 'foreign', 'freetext', 'freetexttable', 'from', 'full', 'function',
+            'goto', 'grant', 'group', 'having', 'holdlock', 'identity', 'identitycol',
+            'identity_insert', 'if', 'in', 'index', 'inner', 'insert', 'intersect', 'into',
+            'is', 'isolation', 'join', 'key', 'kill', 'left', 'level', 'like', 'lineno',
+            'load', 'max', 'min', 'mirrorexit', 'national', 'nocheck', 'nonclustered',
+            'not', 'null', 'nullif', 'of', 'off', 'offsets', 'on', 'once', 'only', 'open',
+            'opendatasource', 'openquery', 'openrowset', 'openxml', 'option', 'or', 'order',
+            'outer', 'over', 'percent', 'perm', 'permanent', 'pipe', 'pivot', 'plan', 'precision',
+            'prepare', 'primary', 'print', 'privileges', 'proc', 'procedure', 'processexit',
+            'public', 'raiserror', 'read', 'readtext', 'reconfigure', 'references',
+            'repeatable', 'replication', 'restore', 'restrict', 'return', 'revoke',
+            'right', 'rollback', 'rowcount', 'rowguidcol', 'rule', 'save', 'schema',
+            'select', 'serializable', 'session_user', 'set', 'setuser', 'shutdown', 'some',
+            'statistics', 'sum', 'system_user', 'table', 'tape', 'temp', 'temporary',
+            'textsize', 'then', 'to', 'top', 'tran', 'transaction', 'trigger', 'truncate',
+            'tsequal', 'uncommitted', 'union', 'unique', 'update', 'updatetext', 'use',
+            'user', 'values', 'varying', 'view', 'waitfor', 'when', 'where', 'while',
+            'with', 'work', 'writetext'
+        );
+        return $reserved_words;
+    }
+}
+
+?>
Index: lib/xmldb/XMLDBStatement.class.php
===================================================================
RCS file: lib/xmldb/XMLDBStatement.class.php
diff -N lib/xmldb/XMLDBStatement.class.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/xmldb/XMLDBStatement.class.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,374 @@
+<?php // $Id: XMLDBStatement.class.php,v 1.7 2007/10/10 05:25:14 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represent one XMLDB Statement
+/// (a group of SQL arbitrary sentences)
+/// (only INSERT is allowed for now)
+
+class XMLDBStatement extends XMLDBObject {
+
+    var $table;     // Table we are handling
+    var $type;      // XMLDB_STATEMENT_TYPE
+    var $sentences; // Collection of sentences in the statement
+
+    /**
+     * Creates one new XMLDBStatement
+     */
+    function XMLDBStatement($name) {
+        parent::XMLDBObject($name);
+        $this->table     = NULL;
+        $this->type      = XMLDB_STATEMENT_INCORRECT;
+        $this->sentences = array();
+    }
+
+    /**
+     * Get the statement table
+     */
+    function getTable() {
+        return $this->table;
+    }
+
+    /**
+     * Get the statement type
+     */
+    function getType() {
+        return $this->type;
+    }
+
+    /**
+     * Get the statement sentences
+     */
+    function &getSentences() {
+        return $this->sentences;
+    }
+
+    /**
+     * Set the statement table
+     */
+    function setTable($table) {
+        $this->table = $table;
+    }
+
+    /**
+     * Set the statement type
+     */
+    function setType($type) {
+        $this->type = $type;
+    }
+
+    /**
+     * Add one statement sentence
+     */
+    function addSentence($sentence) {
+        $this->sentences[] = $sentence;
+    }
+
+    /**
+     * Load data from XML to the index
+     */
+    function arr2XMLDBStatement($xmlarr) {
+
+        $result = true;
+
+    /// Debug the table
+    /// traverse_xmlize($xmlarr);                   //Debug
+    /// print_object ($GLOBALS['traverse_array']);  //Debug
+    /// $GLOBALS['traverse_array']="";              //Debug
+
+    /// Process key attributes (table, type, comment, previous, next)
+        if (isset($xmlarr['@']['TABLE'])) {
+            $this->table = strtolower(trim($xmlarr['@']['TABLE']));
+        } else {
+            $this->errormsg = 'Missing TABLE attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+        if (isset($xmlarr['@']['TYPE'])) {
+        /// Check for valid type
+            $type = $this->getXMLDBStatementType(trim($xmlarr['@']['TYPE']));
+            if ($type) {
+                $this->type = $type;
+            } else {
+                $this->errormsg = 'Invalid TYPE attribute';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        } else {
+            $this->errormsg = 'Missing TYPE attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+    /// Look for sentences
+        $sentencesarr = array();
+
+        if (isset($xmlarr['#']['SENTENCES'])) {
+            $sentences = $xmlarr['#']['SENTENCES'][0]['#']['SENTENCE'];
+            if ($sentences) {
+                foreach ($sentences as $sentence) {
+                    if (isset($sentence['@']['TEXT'])) {
+                        $sentencesarr[] = trim($sentence['@']['TEXT']);
+                    } else {
+                        $this->errormsg = 'Missing TEXT attribute in sentence';
+                        $this->debug($this->errormsg);
+                        $result = false;
+                    }
+                }
+            }
+        }
+
+    /// Finally, set the array of sentences
+        $this->sentences = $sentencesarr;
+
+    /// Now, perform some validations over sentences
+    /// XMLDB_STATEMENT_INSERT checks
+        if ($this->type == XMLDB_STATEMENT_INSERT) {
+        /// Separate fields and values into two arrays
+            if ($this->sentences) {
+                foreach ($this->sentences as $sentence) {
+                    $fields = $this->getFieldsFromInsertSentence($sentence);
+                    $values = $this->getValuesFromInsertSentence($sentence);
+                /// Check that we aren't inserting the id field
+                    if (in_array('id', $fields)) {
+                        $this->errormsg = 'Cannot insert the "id" field. It is an autonumeric column';
+                        $this->debug($this->errormsg);
+                        $result = false;
+                    }
+                    if ($result && count($fields) == 0) {
+                        $this->errormsg = 'Missing fields in sentence "' . $sentence . '"';
+                        $this->debug($this->errormsg);
+                        $result = false;
+                    }
+                    if ($result && count($values) == 0) {
+                        $this->errormsg = 'Missing values in sentence "' . $sentence . '"';
+                        $this->debug($this->errormsg);
+                        $result = false;
+                    }
+                    if ($result && count($fields) != count($values)) {
+                        $this->errormsg = 'Incorrect number of fields (' .implode(', ', $fields) . ') or values (' . implode(', ', $values) . ')';
+                        $this->debug($this->errormsg);
+                        $result = false;
+                    }
+                }
+            }
+        } else {
+        /// Sentences different from INSERT are not valid for now
+            $this->errormsg = 'Only INSERT statements are supported';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+        if (isset($xmlarr['@']['COMMENT'])) {
+            $this->comment = trim($xmlarr['@']['COMMENT']);
+        }
+
+        if (isset($xmlarr['@']['PREVIOUS'])) {
+            $this->previous = trim($xmlarr['@']['PREVIOUS']);
+        }
+
+        if (isset($xmlarr['@']['NEXT'])) {
+            $this->next = trim($xmlarr['@']['NEXT']);
+        }
+
+    /// Set some attributes
+        if ($result) {
+            $this->loaded = true;
+        }
+        $this->calculateHash();
+        return $result;
+    }
+
+    /**
+     * This function returns the correct XMLDB_STATEMENT_XXX value for the
+     * string passed as argument
+     */
+    function getXMLDBStatementType($type) {
+
+        $result = XMLDB_STATEMENT_INCORRECT;
+
+        switch (strtolower($type)) {
+            case 'insert':
+                $result = XMLDB_STATEMENT_INSERT;
+                break;
+            case 'update':
+                $result = XMLDB_STATEMENT_UPDATE;
+                break;
+            case 'delete':
+                $result = XMLDB_STATEMENT_DELETE;
+                break;
+            case 'custom':
+                $result = XMLDB_STATEMENT_CUSTOM;
+                break;
+        }
+    /// Return the normalized XMLDB_STATEMENT
+        return $result;
+    }
+
+    /**
+     * This function returns the correct name value for the
+     * XMLDB_STATEMENT_XXX passed as argument
+     */
+    function getXMLDBStatementName($type) {
+
+        $result = '';
+
+        switch (strtolower($type)) {
+            case XMLDB_STATEMENT_INSERT:
+                $result = 'insert';
+                break;
+            case XMLDB_STATEMENT_UPDATE:
+                $result = 'update';
+                break;
+            case XMLDB_STATEMENT_DELETE:
+                $result = 'delete';
+                break;
+            case XMLDB_STATEMENT_CUSTOM:
+                $result = 'custom';
+                break;
+        }
+    /// Return the normalized name
+        return $result;
+    }
+
+    /**
+     * This function calculate and set the hash of one XMLDBStatement
+     */
+     function calculateHash($recursive = false) {
+        if (!$this->loaded) {
+            $this->hash = NULL;
+        } else {
+            $key = $this->table . $this->type . implode (', ', $this->sentences);
+            $this->hash = md5($key);
+        }
+    }
+
+    /**
+     * This function will output the XML text for one statement
+     */
+    function xmlOutput() {
+        $o = '';
+        $o.= '    <STATEMENT NAME="' . $this->name . '" TYPE="' . XMLDBStatement::getXMLDBStatementName($this->type) . '" TABLE="' . $this->table . '"';
+        if ($this->comment) {
+            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
+        }
+        if ($this->previous) {
+            $o.= ' PREVIOUS="' . $this->previous . '"';
+        }
+        if ($this->next) {
+            $o.= ' NEXT="' . $this->next . '"';
+        }
+        if ($this->sentences) {
+            $o.= '>' . "\n";
+            $o.= '      <SENTENCES>' . "\n";
+            foreach ($this->sentences as $sentence) {
+                $o.= '        <SENTENCE TEXT="' . htmlspecialchars($sentence) . '" />' . "\n";
+            }
+            $o.= '      </SENTENCES>' . "\n";
+            $o.= '    </STATEMENT>' . "\n";
+        } else {
+            $o.= '/>' . "\n";
+        }
+
+        return $o;
+    }
+
+    /**
+     * This function will set all the attributes of the XMLDBIndex object
+     * based on information passed in one ADOindex
+     */
+    function setFromADOIndex($adoindex) {
+
+    /// Set the unique field
+        $this->unique = false;
+    /// Set the fields
+        $this->fields = $adoindex['columns'];
+    /// Some more fields
+        $this->loaded = true;
+        $this->changed = true;
+    }
+
+    /**
+     * Shows info in a readable format
+     */
+    function readableInfo() {
+        $o = '';
+    /// unique
+        if ($this->unique) {
+            $o .= 'unique';
+        } else {
+            $o .= 'not unique';
+        }
+    /// fields
+        $o .= ' (' . implode(', ', $this->fields) . ')';
+
+        return $o;
+    }
+
+    /**
+     * This function will return an array of fields from one INSERT sentence
+     */
+    function getFieldsFromInsertSentence($sentence) {
+
+        $fields = array();
+
+    /// Get first part from the sentence (before VALUES)
+        preg_match('/^\((.*)\)\s+VALUES/is', $sentence, $matches);
+        if (isset($matches[1])) {
+            $part = $matches[1];
+        /// Convert the comma separated string to an array
+            $arr = $this->comma2array($part);
+            if ($arr) {
+                $fields = $arr;
+            }
+        }
+
+        return $fields;
+    }
+
+    /**
+     * This function will return an array of values from one INSERT sentence
+     */
+    function getValuesFromInsertSentence($sentence) {
+
+        $values = array();
+
+    /// Get second part from the sentence (after VALUES)
+        preg_match('/VALUES\s*\((.*)\)$/is', $sentence, $matches);
+        if (isset($matches[1])) {
+            $part = $matches[1];
+        /// Convert the comma separated string to an array
+            $arr = $this->comma2array($part);
+            if ($arr) {
+                $values = $arr;
+            }
+        }
+
+        return $values;
+    }
+}
+
+?>
Index: lib/dml/mysql_adodb_moodle_database.php
===================================================================
RCS file: lib/dml/mysql_adodb_moodle_database.php
diff -N lib/dml/mysql_adodb_moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/mysql_adodb_moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,26 @@
+<?php  //$Id:$
+
+require_once($CFG->libdir.'/dml/moodle_database.php');
+require_once($CFG->libdir.'/dml/adodb_moodle_database.php');
+require_once($CFG->libdir.'/dml/mysqli_adodb_moodle_database.php');
+
+/**
+ * Legacy MySQL database class using adodb backend
+ * @package dmlib
+ */
+class mysql_adodb_moodle_database extends mysqli_adodb_moodle_database {
+    protected $columns = array();
+
+    function __construct ($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        parent::__construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix);
+    }
+
+    /**
+     * Returns database type
+     * @return string db type mysql, mysqli, postgres7
+     */
+    protected function get_dbtype() {
+        return 'mysql';
+    }
+
+}
Index: lib/ddl/postgres_sql_generator.php
===================================================================
RCS file: lib/ddl/postgres_sql_generator.php
diff -N lib/ddl/postgres_sql_generator.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/ddl/postgres_sql_generator.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,580 @@
+<?php // $Id: postgres7.class.php,v 1.36 2007/10/10 05:25:28 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once($CFG->libdir.'/ddl/sql_generator.php');
+
+/// This class generate SQL code to be used against PostgreSQL
+/// It extends XMLDBgenerator so everything can be
+/// overriden as needed to generate correct SQL.
+
+class postgres_sql_generator extends sql_generator {
+
+/// Only set values that are different from the defaults present in XMLDBgenerator
+
+    public $number_type = 'NUMERIC';    // Proper type for NUMBER(x) in this DB
+
+    public $unsigned_allowed = false;    // To define in the generator must handle unsigned information
+    public $default_for_char = '';      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
+
+    public $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
+    public $sequence_name = 'BIGSERIAL'; //Particular name for inline sequences in this generator
+    public $sequence_name_small = 'SERIAL'; //Particular name for inline sequences in this generator
+    public $sequence_only = true; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable
+
+    public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
+
+    public $rename_index_sql = 'ALTER TABLE OLDINDEXNAME RENAME TO NEWINDEXNAME'; //SQL sentence to rename one index
+                                      //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dinamically replaced
+
+    public $rename_key_sql = null; //SQL sentence to rename one key (PostgreSQL doesn't support this!)
+                                          //TABLENAME, OLDKEYNAME, NEWKEYNAME are dinamically replaced
+
+    /**
+     * Creates one new XMLDBpostgres7
+     */
+    public function __construct($mdb) {
+        parent::__construct($mdb);
+    }
+
+    /**
+     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
+     */
+    public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
+
+        switch ($xmldb_type) {
+            case XMLDB_TYPE_INTEGER:    // From http://www.postgresql.org/docs/7.4/interactive/datatype.html
+                if (empty($xmldb_length)) {
+                    $xmldb_length = 10;
+                }
+                if ($xmldb_length > 9) {
+                    $dbtype = 'BIGINT';
+                } else if ($xmldb_length > 4) {
+                    $dbtype = 'INTEGER';
+                } else {
+                    $dbtype = 'SMALLINT';
+                }
+                break;
+            case XMLDB_TYPE_NUMBER:
+                $dbtype = $this->number_type;
+                if (!empty($xmldb_length)) {
+                    $dbtype .= '(' . $xmldb_length;
+                    if (!empty($xmldb_decimals)) {
+                        $dbtype .= ',' . $xmldb_decimals;
+                    }
+                    $dbtype .= ')';
+                }
+                break;
+            case XMLDB_TYPE_FLOAT:
+                $dbtype = 'DOUBLE PRECISION';
+                if (!empty($xmldb_decimals)) {
+                    if ($xmldb_decimals < 6) {
+                        $dbtype = 'REAL';
+                    }
+                }
+                break;
+            case XMLDB_TYPE_CHAR:
+                $dbtype = 'VARCHAR';
+                if (empty($xmldb_length)) {
+                    $xmldb_length='255';
+                }
+                $dbtype .= '(' . $xmldb_length . ')';
+                break;
+            case XMLDB_TYPE_TEXT:
+                $dbtype = 'TEXT';
+                break;
+            case XMLDB_TYPE_BINARY:
+                $dbtype = 'BYTEA';
+                break;
+            case XMLDB_TYPE_DATETIME:
+                $dbtype = 'TIMESTAMP';
+                break;
+        }
+        return $dbtype;
+    }
+
+    /**
+     * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
+     */
+    public function getEnumExtraSQL($xmldb_table, $xmldb_field) {
+
+        $sql = 'CONSTRAINT ' . $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'ck');
+        $sql.= ' CHECK (' . $this->getEncQuoted($xmldb_field->getName()) . ' IN (' . implode(', ', $xmldb_field->getEnumValues()) . '))';
+
+        return $sql;
+    }
+
+    /**
+     * Returns the code (in array) needed to add one comment to the table
+     */
+    function getCommentSQL ($xmldb_table) {
+
+        $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
+        $comment.= " IS '" . $this->addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
+
+        return array($comment);
+    }
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on table rename
+     */
+    public function getRenameTableExtraSQL($xmldb_table, $newname) {
+
+        $results = array();
+
+        $newt = new XMLDBTable($newname);
+
+        $xmldb_field = new XMLDBField('id'); // Fields having sequences should be exclusively, id.
+
+        $oldseqname = $this->getTableName($xmldb_table) . '_' . $xmldb_field->getName() . '_seq';
+        $newseqname = $this->getTableName($newt) . '_' . $xmldb_field->getName() . '_seq';
+
+    /// Rename de sequence
+        $results[] = 'ALTER TABLE ' . $oldseqname . ' RENAME TO ' . $newseqname;
+
+    /// Rename all the check constraints in the table
+        $oldtablename = $this->getTableName($xmldb_table);
+        $newtablename = $this->getTableName($newt);
+
+        $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
+        $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
+
+        if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
+            foreach ($constraints as $constraint) {
+            /// Drop the old constraint
+                $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
+            /// Calculate the new constraint name
+                $newconstraintname = str_replace($oldconstraintprefix, $newconstraintprefix, $constraint->name);
+            /// Add the new constraint
+                $results[] = 'ALTER TABLE ' . $newtablename . ' ADD CONSTRAINT ' . $newconstraintname .
+                             ' CHECK ' . $constraint->description;
+             }
+         }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add the field to the table
+     * PostgreSQL is pretty standard but with one severe restriction under 7.4 that forces us to overload
+     * this function: Default clause is not allowed when adding fields.
+     *
+     * This function can be safely removed once min req. for PG will be 8.0
+     */
+    public function getAddFieldSQL($xmldb_table, $xmldb_field) {
+
+        $results = array();
+
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+        $defaultvalue = $xmldb_field->getDefault();
+
+    /// Save old flags
+        $old_skip_default = $this->alter_column_skip_default;
+        $old_skip_notnull = $this->alter_column_skip_notnull;
+
+    /// Prevent default clause and launch parent getAddField()
+        $this->alter_column_skip_default = true;
+        $this->alter_column_skip_notnull = true;
+        $results = parent::getAddFieldSQL($xmldb_table, $xmldb_field);
+
+    /// Re-set old flags
+        $this->alter_column_skip_default = $old_skip_default;
+        $this->alter_column_skip_notnull = $old_skip_notnull;
+
+    /// Add default (only if not skip_default)
+        if (!$this->alter_column_skip_default) {
+            $default_clause = $this->getDefaultClause($xmldb_field);
+            if ($default_clause) {
+                $sql = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET' . $default_clause; /// Add default clause
+                $results[] = $sql;
+            }
+
+        /// Update default value (if exists) to all the records
+            if ($defaultvalue !== null) {
+                if (!is_numeric($defaultvalue)) {
+                    $defaultvalue = "'".$this->addslashes($defaultvalue)."'";
+                }
+                $sql = 'UPDATE ' . $tablename . ' SET ' . $fieldname . '=' . $defaultvalue;
+                $results[] = $sql;
+            }
+        }
+
+    /// Add not null (only if no skip_notnull)
+        if (!$this->alter_column_skip_notnull) {
+            if ($xmldb_field->getNotnull()) {
+                $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET NOT NULL'; /// Add not null
+            }
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table
+     * PostgreSQL has some severe limits:
+     *     - Any change of type or precision requires a new temporary column to be created, values to
+     *       be transfered potentially casting them, to apply defaults if the column is not null and
+     *       finally, to rename it
+     *     - Changes in null/not null require the SET/DROP NOT NULL clause
+     *     - Changes in default require the SET/DROP DEFAULT clause
+     */
+    public function getAlterFieldSQL($xmldb_table, $xmldb_field) {
+
+        global $db;
+
+        $results = array(); /// To store all the needed SQL commands
+
+    /// Get the normla names of the table and field
+        $tablename = $xmldb_table->getName();
+        $fieldname = $xmldb_field->getName();
+
+    /// Take a look to field metadata
+        $meta = $this->mdb->get_columns($xmldb_table->getName());
+        $metac = $meta[$xmldb_field->getName()];
+        $oldmetatype = $metac->meta_type;
+        $oldlength = $metac->max_length;
+        $olddecimals = empty($metac->scale) ? null : $metac->scale;
+        $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
+        $olddefault = empty($metac->has_default) ? null : $metac->default_value;
+
+        $typechanged = true;  //By default, assume that the column type has changed
+        $precisionchanged = true;  //By default, assume that the column precision has changed
+        $decimalchanged = true;  //By default, assume that the column decimal has changed
+        $defaultchanged = true;  //By default, assume that the column default has changed
+        $notnullchanged = true;  //By default, assume that the column notnull has changed
+
+        $from_temp_fields = false; //By default don't assume we are going to use temporal fields
+
+    /// Detect if we are changing the type of the column
+        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_NUMBER  && $oldmetatype == 'N') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_FLOAT   && $oldmetatype == 'F') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_CHAR    && $oldmetatype == 'C') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && $oldmetatype == 'X') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_BINARY  && $oldmetatype == 'B')) {
+            $typechanged = false;
+        }
+    /// Detect if we are changing the precision
+        if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
+            ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
+            ($oldlength == -1) ||
+            ($xmldb_field->getLength() == $oldlength)) {
+            $precisionchanged = false;
+        }
+    /// Detect if we are changing the decimals
+        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) ||
+            ($xmldb_field->getType() == XMLDB_TYPE_CHAR) ||
+            ($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
+            ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
+            (!$xmldb_field->getDecimals()) ||
+            (!$olddecimals) ||
+            ($xmldb_field->getDecimals() == $olddecimals)) {
+            $decimalchanged = false;
+        }
+    /// Detect if we are changing the default
+        if (($xmldb_field->getDefault() === null && $olddefault === null) ||
+            ($xmldb_field->getDefault() === $olddefault)) {
+            $defaultchanged = false;
+        }
+    /// Detect if we are changing the nullability
+        if (($xmldb_field->getNotnull() === $oldnotnull)) {
+            $notnullchanged = false;
+        }
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// TODO: Some combinations like
+    /// TODO: integer->integer
+    /// TODO: integer->text
+    /// TODO: number->text
+    /// TODO: text->text
+    /// TODO: do not require the use of temp columns, because PG 8.0 supports them automatically
+    /// TODO: with a simple "alter table zzz alter column yyy type new specs"
+    /// TODO: Must be implemented that way. Eloy 09/2007
+
+    /// If the type or the precision or the decimals have changed, then we need to:
+    ///     - create one temp column with the new specs
+    ///     - fill the new column with the values from the old one (casting if needed)
+    ///     - drop the old column
+    ///     - rename the temp column to the original name
+        if ($typechanged || $precisionchanged || $decimalchanged) {
+            $tempcolname = $xmldb_field->getName() . '_alter_column_tmp';
+        /// Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints
+            $this->alter_column_skip_notnull = true;
+            $this->alter_column_skip_default = true;
+            $xmldb_field->setName($tempcolname);
+        /// Create the temporal column
+            $results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field));
+        /// Detect some basic casting options
+            if ((substr($oldmetatype, 0, 1) == 'C' && $xmldb_field->getType() == XMLDB_TYPE_NUMBER) ||
+                (substr($oldmetatype, 0, 1) == 'C' && $xmldb_field->getType() == XMLDB_TYPE_FLOAT)) {
+                $copyorigin = 'CAST(CAST('.$fieldname.' AS TEXT) AS REAL)'; //From char to number or float
+            } else if ((substr($oldmetatype, 0, 1) == 'C' && $xmldb_field->getType() == XMLDB_TYPE_INTEGER)) {
+                $copyorigin = 'CAST(CAST('.$fieldname.' AS TEXT) AS INTEGER)'; //From char to integer
+            } else {
+                $copyorigin = $fieldname; //Direct copy between columns
+            }
+        /// Copy contents from original col to the temporal one
+            $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $copyorigin;
+        /// Drop the old column
+            $xmldb_field->setName($fieldname); //Set back the original field name
+            $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
+        /// Rename the temp column to the original one
+            $results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname;
+        /// Mark we have performed one change based in temp fields
+            $from_temp_fields = true;
+        }
+    /// If the default has changed or we have used one temp field
+        if ($defaultchanged || $from_temp_fields) {
+            $default_clause = $this->getDefaultClause($xmldb_field);
+            if ($default_clause) {
+                $sql = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET' . $default_clause; /// Add default clause
+                $results[] = $sql;
+            } else {
+                if (!$from_temp_fields) { /// Only drop default if we haven't used the temp field, i.e. old column
+                    $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' DROP DEFAULT'; /// Drop default clause
+                }
+            }
+        }
+    /// If the not null has changed or we have used one temp field
+        if ($notnullchanged || $from_temp_fields) {
+            if ($xmldb_field->getNotnull()) {
+                $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' SET NOT NULL';
+            } else {
+                $results[] = 'ALTER TABLE ' . $tablename . ' ALTER COLUMN ' . $fieldname . ' DROP NOT NULL';
+            }
+        }
+
+    /// Return the results
+        return $results;
+    }
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on field rename
+     */
+    public function getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname) {
+
+        $results = array();
+
+    /// If the field is enum, drop and re-create the check constraint
+        if ($xmldb_field->getEnum()) {
+        /// Drop the current enum
+            $results = array_merge($results, $this->getDropEnumSQL($xmldb_table, $xmldb_field));
+        /// Change field name (over a clone to avoid some potential problems later)
+            $new_xmldb_field = clone($xmldb_field);
+            $new_xmldb_field->setName($newname);
+        /// Recreate the enum
+            $results = array_merge($results, $this->getCreateEnumSQL($xmldb_table, $new_xmldb_field));
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public function getCreateEnumSQL($xmldb_table, $xmldb_field) {
+    /// All we have to do is to create the check constraint
+        return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
+                     ' ADD ' . $this->getEnumExtraSQL($xmldb_table, $xmldb_field));
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public function getDropEnumSQL($xmldb_table, $xmldb_field) {
+    /// Let's introspect to know the real name of the check constraint
+        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
+            $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
+            $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
+        /// All we have to do is to drop the check constraint
+            return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
+                     ' DROP CONSTRAINT ' . $constraint_name);
+        } else { /// Constraint not found. Nothing to do
+            return array();
+        }
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
+    /// Just a wrapper over the getAlterFieldSQL() function for PostgreSQL that
+    /// is capable of handling defaults
+        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
+    /// Just a wrapper over the getAlterFieldSQL() function for PostgreSQL that
+    /// is capable of handling defaults
+        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
+    }
+
+    /**
+     * Given one XMLDBTable returns one array with all the check constrainsts
+     * in the table (fetched from DB)
+     * Optionally the function allows one xmldb_field to be specified in
+     * order to return only the check constraints belonging to one field.
+     * Each element contains the name of the constraint and its description
+     * If no check constraints are found, returns an empty array
+     */
+    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
+
+        $results = array();
+
+        $tablename = $this->getTableName($xmldb_table);
+
+        if ($constraints = get_records_sql("SELECT co.conname AS name, co.consrc AS description
+                                              FROM pg_constraint co,
+                                                   pg_class cl
+                                             WHERE co.conrelid = cl.oid
+                                               AND co.contype = 'c'
+                                               AND cl.relname = '{$tablename}'")) {
+            foreach ($constraints as $constraint) {
+                $results[$constraint->name] = $constraint;
+            }
+        }
+
+    /// Filter by the required field if specified
+        if ($xmldb_field) {
+            $filtered_results = array();
+            $filter = $xmldb_field->getName();
+        /// Lets clean a bit each constraint description, looking for the filtered field
+            foreach ($results as $key => $result) {
+                $description = preg_replace('/\("(.*?)"\)/', '($1)', $result->description);// Double quotes out
+                $description = preg_replace('/[\(\)]/', '', $description);                 // Parenthesis out
+                $description = preg_replace('/::[a-z]+/i', '', $description);              // Casts out
+                $description = preg_replace("/({$filter})/i", '@$1@', $description);
+                $description = trim(preg_replace('/ or /i', ' OR ', $description));        // Uppercase or & trim
+            /// description starts by @$filter@ assume it's a constraint beloging to the field
+                if (preg_match("/^@{$filter}@/i", $description)) {
+                    $filtered_results[$key] = $result;
+                }
+            }
+        /// Assign filtered results to the final results array
+            $results =  $filtered_results;
+        }
+
+        return $results;
+    }
+
+/**
+ * Given one XMLDBTable returns one string with the sequence of the table
+ * in the table (fetched from DB)
+ * The sequence name for Postgres has one standard name convention:
+ *     tablename_fieldname_seq
+ * so we just calculate it and confirm it's present in pg_class
+ * If no sequence is found, returns false
+ */
+function getSequenceFromDB($xmldb_table) {
+
+    $tablename = $this->getTableName($xmldb_table);
+    $sequencename = $tablename . '_id_seq';
+
+    if (!get_record_sql("SELECT *
+                     FROM pg_class
+                     WHERE relname = '{$sequencename}'
+                       AND relkind = 'S'")) {
+        $sequencename = false;
+    }
+
+    return $sequencename;
+}
+
+    /**
+     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
+     * return if such name is currently in use (true) or no (false)
+     * (invoked from getNameForObject()
+     */
+    public function isNameInUse($object_name, $type, $table_name) {
+        switch($type) {
+            case 'ix':
+            case 'uix':
+            case 'seq':
+                if ($check = get_records_sql("SELECT relname
+                                              FROM pg_class
+                                              WHERE lower(relname) = '" . strtolower($object_name) . "'")) {
+                    return true;
+                }
+                break;
+            case 'pk':
+            case 'uk':
+            case 'fk':
+            case 'ck':
+                if ($check = get_records_sql("SELECT conname
+                                              FROM pg_constraint
+                                              WHERE lower(conname) = '" . strtolower($object_name) . "'")) {
+                    return true;
+                }
+                break;
+            case 'trg':
+                if ($check = get_records_sql("SELECT tgname
+                                              FROM pg_trigger
+                                              WHERE lower(tgname) = '" . strtolower($object_name) . "'")) {
+                    return true;
+                }
+                break;
+        }
+        return false; //No name in use found
+    }
+
+    /**
+     * Returns an array of reserved words (lowercase) for this DB
+     */
+    public static function getReservedWords() {
+    /// This file contains the reserved words for PostgreSQL databases
+    /// http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
+        $reserved_words = array (
+            'all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc',
+            'asymmetric', 'authorization', 'between', 'binary', 'both', 'case',
+            'cast', 'check', 'collate', 'column', 'constraint', 'create', 'cross',
+            'current_date', 'current_role', 'current_time', 'current_timestamp',
+            'current_user', 'default', 'deferrable', 'desc', 'distinct', 'do',
+            'else', 'end', 'except', 'false', 'for', 'foreign', 'freeze', 'from',
+            'full', 'grant', 'group', 'having', 'ilike', 'in', 'initially', 'inner',
+            'intersect', 'into', 'is', 'isnull', 'join', 'leading', 'left', 'like',
+            'limit', 'localtime', 'localtimestamp', 'natural', 'new', 'not',
+            'notnull', 'null', 'off', 'offset', 'old', 'on', 'only', 'or', 'order',
+            'outer', 'overlaps', 'placing', 'primary', 'references', 'right', 'select',
+            'session_user', 'similar', 'some', 'symmetric', 'table', 'then', 'to',
+            'trailing', 'true', 'union', 'unique', 'user', 'using', 'verbose',
+            'when', 'where'
+        );
+        return $reserved_words;
+    }
+}
+
+?>
Index: lib/ddl/oracle_sql_generator.php
===================================================================
RCS file: lib/ddl/oracle_sql_generator.php
diff -N lib/ddl/oracle_sql_generator.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/ddl/oracle_sql_generator.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,690 @@
+<?php // $Id: oci8po.class.php,v 1.39 2008/04/26 22:46:03 stronk7 Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once($CFG->libdir.'/ddl/sql_generator.php');
+
+/// This class generate SQL code to be used against Oracle
+/// It extends XMLDBgenerator so everything can be
+/// overriden as needed to generate correct SQL.
+
+class oracle_sql_generator extends sql_generator {
+
+/// Only set values that are different from the defaults present in XMLDBgenerator
+
+    public $statement_end = "\n/"; // String to be automatically added at the end of each statement
+                                // Using "/" because the standard ";" isn't good for stored procedures (triggers)
+
+    public $number_type = 'NUMBER';    // Proper type for NUMBER(x) in this DB
+
+    public $unsigned_allowed = false;    // To define in the generator must handle unsigned information
+    public $default_for_char = ' ';      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
+                                      // Using this whitespace here because Oracle doesn't distinguish empty and null! :-(
+
+    public $drop_default_value_required = true; //To specify if the generator must use some DEFAULT clause to drop defaults
+    public $drop_default_value = NULL; //The DEFAULT clause required to drop defaults
+
+    public $default_after_null = false;  //To decide if the default clause of each field must go after the null clause
+
+    public $sequence_extra_code = true; //Does the generator need to add extra code to generate the sequence fields
+    public $sequence_name = ''; //Particular name for inline sequences in this generator
+
+    public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
+
+    public $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY (COLUMNSPECS)'; //The SQL template to alter columns
+
+    /**
+     * Creates one new XMLDBoci8po
+     */
+    public function __construct($mdb) {
+        parent::__construct($mdb);
+    }
+
+    /**
+     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
+     */
+    public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
+
+        switch ($xmldb_type) {
+            case XMLDB_TYPE_INTEGER:    // From http://www.postgresql.org/docs/7.4/interactive/datatype.html
+                if (empty($xmldb_length)) {
+                    $xmldb_length = 10;
+                }
+                $dbtype = 'NUMBER(' .  $xmldb_length . ')';
+                break;
+            case XMLDB_TYPE_NUMBER:
+                $dbtype = $this->number_type;
+            /// 38 is the max allowed
+                if ($xmldb_length > 38) {
+                    $xmldb_length = 38;
+                }
+                if (!empty($xmldb_length)) {
+                    $dbtype .= '(' . $xmldb_length;
+                    if (!empty($xmldb_decimals)) {
+                        $dbtype .= ',' . $xmldb_decimals;
+                    }
+                    $dbtype .= ')';
+                }
+                break;
+            case XMLDB_TYPE_FLOAT:
+                $dbtype = 'NUMBER';
+                break;
+            case XMLDB_TYPE_CHAR:
+                $dbtype = 'VARCHAR2';
+                if (empty($xmldb_length)) {
+                    $xmldb_length='255';
+                }
+                $dbtype .= '(' . $xmldb_length . ')';
+                break;
+            case XMLDB_TYPE_TEXT:
+                $dbtype = 'CLOB';
+                break;
+            case XMLDB_TYPE_BINARY:
+                $dbtype = 'BLOB';
+                break;
+            case XMLDB_TYPE_DATETIME:
+                $dbtype = 'DATE';
+                break;
+        }
+        return $dbtype;
+    }
+
+    /**
+     * This function will create the temporary table passed as argument with all its
+     * fields/keys/indexes/sequences, everything based in the XMLDB object
+     *
+     * TRUNCATE the table immediately after creation. A previous process using
+     * the same persistent connection may have created the temp table and failed to
+     * drop it. In that case, the table will exist, and create_temp_table() will
+     * will succeed.
+     *
+     * NOTE: The return value is the tablename - some DBs (MSSQL at least) use special
+     * names for temp tables.
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return string tablename on success, false on error
+     */
+    function create_temp_table($xmldb_table, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect create_table() $xmldb_table parameter');
+            return false;
+        }
+
+    /// Check table doesn't exist
+        if ($this->table_exists($xmldb_table)) {
+            debugging('Table ' . $xmldb_table->getName() .
+                      ' already exists. Create skipped', DEBUG_DEVELOPER);
+            return $xmldb_table->getName(); //Table exists, nothing to do
+        }
+
+        if (!$sqlarr = $this->getCreateTableSQL($xmldb_table)) {
+            return $xmldb_table->getName(); //Empty array = nothing to do = no error
+        }
+
+        $sqlarr = preg_replace('/^CREATE/', "CREATE GLOBAL TEMPORARY", $sqlarr);
+
+        if (execute_sql_arr($sqlarr, $continue, $feedback)) {
+            return $xmldb_table->getName();
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
+     */
+    public function getEnumExtraSQL($xmldb_table, $xmldb_field) {
+
+        $sql = 'CONSTRAINT ' . $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'ck');
+        $sql.= ' CHECK (' . $this->getEncQuoted($xmldb_field->getName()) . ' IN (' . implode(', ', $xmldb_field->getEnumValues()) . '))';
+
+        return $sql;
+    }
+
+    /**
+     * Returns the code needed to create one sequence for the xmldb_table and xmldb_field passes
+     */
+    public function getCreateSequenceSQL($xmldb_table, $xmldb_field) {
+
+        $results = array();
+
+        $sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
+
+        $sequence = "CREATE SEQUENCE " . $sequence_name;
+        $sequence.= "\n    START WITH 1";
+        $sequence.= "\n    INCREMENT BY 1";
+        $sequence.= "\n    NOMAXVALUE";
+
+        $results[] = $sequence;
+
+        $results = array_merge($results, $this->getCreateTriggerSQL ($xmldb_table, $xmldb_field));
+
+        return $results;
+    }
+
+    /**
+     * Returns the code needed to create one trigger for the xmldb_table and xmldb_field passed
+     */
+    public function getCreateTriggerSQL($xmldb_table, $xmldb_field) {
+
+        $trigger_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'trg');
+        $sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
+
+        $trigger = "CREATE TRIGGER " . $trigger_name;
+        $trigger.= "\n    BEFORE INSERT";
+        $trigger.= "\nON " . $this->getTableName($xmldb_table);
+        $trigger.= "\n    FOR EACH ROW";
+        $trigger.= "\nBEGIN";
+        $trigger.= "\n    IF :new." . $this->getEncQuoted($xmldb_field->getName()) . ' IS NULL THEN';
+        $trigger.= "\n        SELECT " . $sequence_name . '.nextval INTO :new.' . $this->getEncQuoted($xmldb_field->getName()) . " FROM dual;";
+        $trigger.= "\n    END IF;";
+        $trigger.= "\nEND;";
+
+        return array($trigger);
+    }
+
+    /**
+     * Returns the code needed to drop one sequence for the xmldb_table and xmldb_field passed
+     * Can, optionally, specify if the underlying trigger will be also dropped
+     */
+    public function getDropSequenceSQL($xmldb_table, $xmldb_field, $include_trigger=false) {
+
+        $sequence_name = $this->getSequenceFromDB($xmldb_table);
+
+        $sequence = "DROP SEQUENCE " . $sequence_name;
+
+        $trigger_name = $this->getTriggerFromDB($xmldb_table);
+
+        $trigger = "DROP TRIGGER " . $trigger_name;
+
+        if ($include_trigger) {
+            $result =  array($sequence, $trigger);
+        } else {
+            $result = array($sequence);
+        }
+        return $result;
+    }
+
+    /**
+     * Returns the code (in array) needed to add one comment to the table
+     */
+    function getCommentSQL ($xmldb_table) {
+
+        $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
+        $comment.= " IS '" . $this->addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
+
+        return array($comment);
+    }
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on field rename
+     */
+    public function getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname) {
+
+        $results = array();
+
+    /// If the field is enum, drop and re-create the check constraint
+        if ($xmldb_field->getEnum()) {
+        /// Drop the current enum
+            $results = array_merge($results, $this->getDropEnumSQL($xmldb_table, $xmldb_field));
+        /// Change field name (over a clone to avoid some potential problems later)
+            $new_xmldb_field = clone($xmldb_field);
+            $new_xmldb_field->setName($newname);
+        /// Recreate the enum
+            $results = array_merge($results, $this->getCreateEnumSQL($xmldb_table, $new_xmldb_field));
+        }
+
+        return $results;
+    }
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on table drop
+     */
+    public function getDropTableExtraSQL($xmldb_table) {
+        $xmldb_field = new XMLDBField('id'); // Fields having sequences should be exclusively, id.
+        return $this->getDropSequenceSQL($xmldb_table, $xmldb_field, false);
+    }
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on table rename
+     */
+    public function getRenameTableExtraSQL($xmldb_table, $newname) {
+
+        $results = array();
+
+        $xmldb_field = new XMLDBField('id'); // Fields having sequences should be exclusively, id.
+
+        $oldseqname = $this->getSequenceFromDB($xmldb_table);
+        $newseqname = $this->getNameForObject($newname, $xmldb_field->getName(), 'seq');
+
+    /// Rename de sequence
+        $results[] = 'RENAME ' . $oldseqname . ' TO ' . $newseqname;
+
+        $oldtriggername = $this->getTriggerFromDB($xmldb_table);
+        $newtriggername = $this->getNameForObject($newname, $xmldb_field->getName(), 'trg');
+
+    /// Drop old trigger
+        $results[] = "DROP TRIGGER " . $oldtriggername;
+
+        $newt = new XMLDBTable($newname); /// Temp table for trigger code generation
+
+    /// Create new trigger
+        $results = array_merge($results, $this->getCreateTriggerSQL($newt, $xmldb_field));
+
+    /// Rename all the check constraints in the table
+        $oldtablename = $this->getTableName($xmldb_table);
+        $newtablename = $this->getTableName($newt);
+
+        $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
+        $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
+
+        if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
+            foreach ($constraints as $constraint) {
+            /// Drop the old constraint
+                $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
+            /// Calculate the new constraint name
+                $newconstraintname = str_replace($oldconstraintprefix, $newconstraintprefix, $constraint->name);
+            /// Add the new constraint
+                $results[] = 'ALTER TABLE ' . $newtablename . ' ADD CONSTRAINT ' . $newconstraintname .
+                             ' CHECK (' . $constraint->description . ')';
+            }
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table
+     * Oracle has some severe limits:
+     *     - clob and blob fields doesn't allow type to be specified
+     *     - error is dropped if the null/not null clause is specified and hasn't changed
+     *     - changes in precision/decimals of numeric fields drop an ORA-1440 error
+     */
+    public function getAlterFieldSQL($xmldb_table, $xmldb_field) {
+
+        global $db;
+
+        $results = array(); /// To store all the needed SQL commands
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// Take a look to field metadata
+        $meta = $this->mdb->get_columns($tablename);
+        $metac = $meta[$fieldname];
+        $oldmetatype = $metac->meta_type;
+
+        $oldlength = $metac->max_length;
+    /// To calculate the oldlength if the field is numeric, we need to perform one extra query
+    /// because ADOdb has one bug here. http://phplens.com/lens/lensforum/msgs.php?id=15883
+        if ($oldmetatype == 'N') {
+            $uppertablename = strtoupper($tablename);
+            $upperfieldname = strtoupper($fieldname);
+            if ($col = get_record_sql("SELECT cname, precision
+                                   FROM col
+                                   WHERE tname = '$uppertablename'
+                                     AND cname = '$upperfieldname'")) {
+                $oldlength = $col->precision;
+            }
+        }
+        $olddecimals = empty($metac->scale) ? null : $metac->scale;
+        $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
+        $olddefault = empty($metac->default_value) || strtoupper($metac->default_value) == 'NULL' ? null : $metac->default_value;
+
+        $typechanged = true;  //By default, assume that the column type has changed
+        $precisionchanged = true;  //By default, assume that the column precision has changed
+        $decimalchanged = true;  //By default, assume that the column decimal has changed
+        $defaultchanged = true;  //By default, assume that the column default has changed
+        $notnullchanged = true;  //By default, assume that the column notnull has changed
+
+        $from_temp_fields = false; //By default don't assume we are going to use temporal fields
+
+    /// Detect if we are changing the type of the column
+        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_NUMBER  && $oldmetatype == 'N') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_FLOAT   && $oldmetatype == 'F') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_CHAR    && $oldmetatype == 'C') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && $oldmetatype == 'X') ||
+            ($xmldb_field->getType() == XMLDB_TYPE_BINARY  && $oldmetatype == 'B')) {
+            $typechanged = false;
+        }
+    /// Detect if precision has changed
+        if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
+            ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
+            ($oldlength == -1) ||
+            ($xmldb_field->getLength() == $oldlength)) {
+            $precisionchanged = false;
+        }
+    /// Detect if decimal has changed
+        if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) ||
+            ($xmldb_field->getType() == XMLDB_TYPE_CHAR) ||
+            ($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
+            ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
+            (!$xmldb_field->getDecimals()) ||
+            (!$olddecimals) ||
+            ($xmldb_field->getDecimals() == $olddecimals)) {
+            $decimalchanged = false;
+        }
+    /// Detect if we are changing the default
+        if (($xmldb_field->getDefault() === null && $olddefault === null) ||
+            ($xmldb_field->getDefault() === $olddefault) ||             //Check both equality and
+            ("'" . $xmldb_field->getDefault() . "'" === $olddefault)) {  //Equality with quotes because ADOdb returns the default with quotes
+            $defaultchanged = false;
+        }
+
+    /// Detect if we are changing the nullability
+        if (($xmldb_field->getNotnull() === $oldnotnull)) {
+            $notnullchanged = false;
+        }
+
+    /// If type has changed or precision or decimal has changed and we are in one numeric field
+    ///     - create one temp column with the new specs
+    ///     - fill the new column with the values from the old one
+    ///     - drop the old column
+    ///     - rename the temp column to the original name
+        if (($typechanged) || (($oldmetatype == 'N' || $oldmetatype == 'I')  && ($precisionchanged || $decimalchanged))) {
+            $tempcolname = $xmldb_field->getName() . '_alter_column_tmp';
+        /// Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints
+            $this->alter_column_skip_notnull = true;
+            $this->alter_column_skip_default = true;
+            $xmldb_field->setName($tempcolname);
+        /// Create the temporal column
+            $results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field));
+        /// Copy contents from original col to the temporal one
+            $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $fieldname;
+        /// Drop the old column
+            $xmldb_field->setName($fieldname); //Set back the original field name
+            $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
+        /// Rename the temp column to the original one
+            $results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname;
+        /// Mark we have performed one change based in temp fields
+            $from_temp_fields = true;
+        /// Re-enable the notnull and default sections so the general AlterFieldSQL can use it
+            $this->alter_column_skip_notnull = false;
+            $this->alter_column_skip_default = false;
+        /// Dissable the type section because we have done it with the temp field
+            $this->alter_column_skip_type = true;
+        /// If new field is nullable, nullability hasn't changed
+            if (!$xmldb_field->getNotnull()) {
+                $notnullchanged = false;
+            }
+        /// If new field hasn't default, default hasn't changed
+            if ($xmldb_field->getDefault() === null) {
+                $defaultchanged = false;
+            }
+        }
+
+    /// If type and precision and decimals hasn't changed, prevent the type clause
+        if (!$typechanged && !$precisionchanged && !$decimalchanged) {
+            $this->alter_column_skip_type = true;
+        }
+
+    /// If NULL/NOT NULL hasn't changed
+    /// prevent null clause to be specified
+        if (!$notnullchanged) {
+            $this->alter_column_skip_notnull = true; /// Initially, prevent the notnull clause
+        /// But, if we have used the temp field and the new field is not null, then enforce the not null clause
+            if ($from_temp_fields &&  $xmldb_field->getNotnull()) {
+                $this->alter_column_skip_notnull = false;
+            }
+        }
+    /// If default hasn't changed
+    /// prevent default clause to be specified
+        if (!$defaultchanged) {
+            $this->alter_column_skip_default = true; /// Initially, prevent the default clause
+        /// But, if we have used the temp field and the new field has default clause, then enforce the default clause
+            if ($from_temp_fields) {
+                $default_clause = $this->getDefaultClause($xmldb_field);
+                if ($default_clause) {
+                    $this->alter_column_skip_default = false;
+                }
+            }
+        }
+
+    /// If arriving here, something is not being skiped (type, notnull, default), calculate the standar AlterFieldSQL
+        if (!$this->alter_column_skip_type || !$this->alter_column_skip_notnull || !$this->alter_column_skip_default) {
+            $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field));
+            return $results;
+        }
+
+    /// Finally return results
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public function getCreateEnumSQL($xmldb_table, $xmldb_field) {
+    /// All we have to do is to create the check constraint
+        return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
+                     ' ADD ' . $this->getEnumExtraSQL($xmldb_table, $xmldb_field));
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public function getDropEnumSQL($xmldb_table, $xmldb_field) {
+    /// Let's introspect to know the real name of the check constraint
+        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
+            $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
+            $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
+        /// All we have to do is to drop the check constraint
+            return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
+                     ' DROP CONSTRAINT ' . $constraint_name);
+        } else { /// Constraint not found. Nothing to do
+            return array();
+        }
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
+    /// Just a wrapper over the getAlterFieldSQL() function for Oracle that
+    /// is capable of handling defaults
+        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
+    /// Just a wrapper over the getAlterFieldSQL() function for Oracle that
+    /// is capable of handling defaults
+        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
+    }
+
+    /**
+     * Given one XMLDBTable returns one array with all the check constrainsts
+     * in the table (fetched from DB)
+     * Optionally the function allows one xmldb_field to be specified in
+     * order to return only the check constraints belonging to one field.
+     * Each element contains the name of the constraint and its description
+     * If no check constraints are found, returns an empty array
+     */
+    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
+
+        $results = array();
+
+        $tablename = strtoupper($this->getTableName($xmldb_table));
+
+        if ($constraints = get_records_sql("SELECT lower(c.constraint_name) AS name, c.search_condition AS description
+                                              FROM user_constraints c
+                                             WHERE c.table_name = '{$tablename}'
+                                               AND c.constraint_type = 'C'
+                                               AND c.constraint_name not like 'SYS%'")) {
+            foreach ($constraints as $constraint) {
+                $results[$constraint->name] = $constraint;
+            }
+        }
+
+    /// Filter by the required field if specified
+        if ($xmldb_field) {
+            $filtered_results = array();
+            $filter = $xmldb_field->getName();
+        /// Lets clean a bit each constraint description, looking for the filtered field
+            foreach ($results as $key => $result) {
+            /// description starts by "$filter IN" assume it's a constraint beloging to the field
+                if (preg_match("/^{$filter} IN/i", $result->description)) {
+                    $filtered_results[$key] = $result;
+                }
+            }
+        /// Assign filtered results to the final results array
+            $results =  $filtered_results;
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable returns one string with the sequence of the table
+     * in the table (fetched from DB)
+     * The sequence name for oracle is calculated by looking the corresponding
+     * trigger and retrieving the sequence name from it (because sequences are
+     * independent elements)
+     * If no sequence is found, returns false
+     */
+    public function getSequenceFromDB($xmldb_table) {
+
+         $tablename    = strtoupper($this->getTableName($xmldb_table));
+         $prefixupper  = strtoupper($this->prefix);
+         $sequencename = false;
+
+        if ($trigger = get_record_sql("SELECT trigger_name, trigger_body
+                                         FROM user_triggers
+                                        WHERE table_name = '{$tablename}'
+                                          AND trigger_name LIKE '{$prefixupper}%_ID%_TRG'")) {
+        /// If trigger found, regexp it looking for the sequence name
+            preg_match('/.*SELECT (.*)\.nextval/i', $trigger->trigger_body, $matches);
+            if (isset($matches[1])) {
+                $sequencename = $matches[1];
+            }
+        }
+
+        return $sequencename;
+    }
+
+    /**
+     * Given one XMLDBTable returns one string with the trigger
+     * in the table (fetched from DB)
+     * If no trigger is found, returns false
+     */
+    public function getTriggerFromDB($xmldb_table) {
+
+        $tablename   = strtoupper($this->getTableName($xmldb_table));
+        $prefixupper = strtoupper($this->prefix);
+        $triggername = false;
+
+        if ($trigger = get_record_sql("SELECT trigger_name, trigger_body
+                                         FROM user_triggers
+                                        WHERE table_name = '{$tablename}'
+                                          AND trigger_name LIKE '{$prefixupper}%_ID%_TRG'")) {
+            $triggername = $trigger->trigger_name;
+        }
+
+        return $triggername;
+    }
+
+    /**
+     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
+     * return if such name is currently in use (true) or no (false)
+     * (invoked from getNameForObject()
+     */
+    public function isNameInUse($object_name, $type, $table_name) {
+        switch($type) {
+            case 'ix':
+            case 'uix':
+            case 'seq':
+            case 'trg':
+                if ($check = get_records_sql("SELECT object_name
+                                              FROM user_objects
+                                              WHERE lower(object_name) = '" . strtolower($object_name) . "'")) {
+                    return true;
+                }
+                break;
+            case 'pk':
+            case 'uk':
+            case 'fk':
+            case 'ck':
+                if ($check = get_records_sql("SELECT constraint_name
+                                              FROM user_constraints
+                                              WHERE lower(constraint_name) = '" . strtolower($object_name) . "'")) {
+                    return true;
+                }
+                break;
+        }
+        return false; //No name in use found
+    }
+
+    public function addslashes($s) {
+        // do not use php addslashes() because it depends on PHP quote settings!
+        $s = str_replace("'",  "''", $s);
+        return $s;
+    }
+
+    /**
+     * Returns an array of reserved words (lowercase) for this DB
+     */
+    public static function getReservedWords() {
+    /// This file contains the reserved words for Oracle databases
+    /// from http://download-uk.oracle.com/docs/cd/B10501_01/server.920/a96540/ap_keywd.htm
+        $reserved_words = array (
+            'access', 'add', 'all', 'alter', 'and', 'any',
+            'as', 'asc', 'audit', 'between', 'by', 'char',
+            'check', 'cluster', 'column', 'comment',
+            'compress', 'connect', 'create', 'current',
+            'date', 'decimal', 'default', 'delete', 'desc',
+            'distinct', 'drop', 'else', 'exclusive', 'exists',
+            'file', 'float', 'for', 'from', 'grant', 'group',
+            'having', 'identified', 'immediate', 'in',
+            'increment', 'index', 'initial', 'insert',
+            'integer', 'intersect', 'into', 'is', 'level',
+            'like', 'lock', 'long', 'maxextents', 'minus',
+            'mlslabel', 'mode', 'modify', 'noaudit',
+            'nocompress', 'not', 'nowait', 'null', 'number',
+            'of', 'offline', 'on', 'online', 'option', 'or',
+            'order', 'pctfree', 'prior', 'privileges',
+            'public', 'raw', 'rename', 'resource', 'revoke',
+            'row', 'rowid', 'rownum', 'rows', 'select',
+            'session', 'set', 'share', 'size', 'smallint',
+            'start', 'successful', 'synonym', 'sysdate',
+            'table', 'then', 'to', 'trigger', 'uid', 'union',
+            'unique', 'update', 'user', 'validate', 'values',
+            'varchar', 'varchar2', 'view', 'whenever',
+            'where', 'with'
+        );
+        return $reserved_words;
+    }
+}
+
+?>
Index: lib/dml/mysqli_adodb_moodle_database.php
===================================================================
RCS file: lib/dml/mysqli_adodb_moodle_database.php
diff -N lib/dml/mysqli_adodb_moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/mysqli_adodb_moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,203 @@
+<?php  //$Id:$
+
+require_once($CFG->libdir.'/dml/moodle_database.php');
+require_once($CFG->libdir.'/dml/adodb_moodle_database.php');
+
+/**
+ * Recommended MySQL database class using adodb backend
+ * @package dmlib
+ */
+class mysqli_adodb_moodle_database extends adodb_moodle_database {
+    function __construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        parent::__construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix);
+    }
+
+    protected function configure_dbconnection() {
+        if (!defined('ADODB_ASSOC_CASE')) {
+            define ('ADODB_ASSOC_CASE', 2);
+        }
+        $this->db->SetFetchMode(ADODB_ASSOC_CASE);
+        $this->db->Execute("SET NAMES 'utf8'");
+        return true;
+    }
+
+    /**
+     * Returns database family type
+     * @return string db family name (mysql, postgres, mssql, oracle, etc.)
+     */
+    public function get_dbfamily() {
+        return 'mysql';
+    }
+
+    /**
+     * Returns database type
+     * @return string db type mysql, mysqli, postgres7
+     */
+    protected function get_dbtype() {
+        return 'mysqli';
+    }
+
+    /**
+     * Returns supported query parameter types
+     * @return bitmask
+     */
+    protected function allowed_param_types() {
+        return SQL_PARAMS_QM;
+    }
+
+    /**
+     * This method will introspect inside DB to detect it it's a UTF-8 DB or no
+     * Used from setup.php to set correctly "set names" when the installation
+     * process is performed without the initial and beautiful installer
+     * @return bool true if db in unicode mode
+     */
+    function setup_is_unicodedb() {
+        $rs = $this->db->Execute("SHOW LOCAL VARIABLES LIKE 'character_set_database'");
+        if ($rs && !$rs->EOF) {
+            $records = $rs->GetAssoc(true);
+            $encoding = $records['character_set_database']['Value'];
+            if (strtoupper($encoding) == 'UTF8') {
+                return  true;
+            }
+        }
+        return false;
+    }
+
+    /**
+    /* Tries to change default db encoding to utf8, if empty db
+     * @return bool sucecss
+     */
+    public function change_db_encoding() {
+        // try forcing utf8 collation, if mysql db and no tables present
+        if (!$this->db->Metatables()) {
+            $SQL = 'ALTER DATABASE '.$this->dbname.' CHARACTER SET utf8';
+            $this->db->Execute($SQL);
+            if ($this->setup_is_unicodedb()) {
+                $this->configure_dbconnection();
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Insert a record into a table and return the "id" field if required,
+     * Some conversions and safety checks are carried out. Lobs are supported.
+     * If the return ID isn't required, then this just reports success as true/false.
+     * $data is an object containing needed data
+     * @param string $table The database table to be inserted into
+     * @param object $data A data object with values for one or more fields in the record
+     * @param bool $returnid Should the id of the newly created record entry be returned? If this option is not requested then true/false is returned.
+     * @param bool $bulk true means repeated inserts expected
+     * @return mixed success or new ID
+     */
+    public function insert_record($table, $dataobject, $returnid=true, $bulk=false) {
+        if (!is_object($dataobject)) {
+            $dataobject = (object)$dataobject;
+        }
+
+        $columns = $this->get_columns($table);
+
+        unset($dataobject->id);
+        $cleaned = array();
+
+        foreach ($dataobject as $field=>$value) {
+            if (!isset($columns[$field])) {
+                continue;
+            }
+            if (is_bool($value)) {
+                $value = (int)$value; // prevent "false" problems
+            }
+            $cleaned[$field] = $value;
+        }
+
+        if (empty($cleaned)) {
+            return false;
+        }
+
+        return $this->insert_record_raw($table, $cleaned, $returnid, $bulk);
+    }
+
+    /**
+     * Update a record in a table
+     *
+     * $dataobject is an object containing needed data
+     * Relies on $dataobject having a variable "id" to
+     * specify the record to update
+     *
+     * @param string $table The database table to be checked against.
+     * @param object $dataobject An object with contents equal to fieldname=>fieldvalue. Must have an entry for 'id' to map to the table specified.
+     * @param bool true means repeated updates expected
+     * @return bool success
+     */
+    public function update_record($table, $dataobject, $bulk=false) {
+        if (!is_object($dataobject)) {
+            $dataobject = (object)$dataobject;
+        }
+
+        if (!isset($dataobject->id) ) {
+            return false;
+        }
+
+        $columns = $this->get_columns($table);
+        $cleaned = array();
+
+        foreach ($dataobject as $field=>$value) {
+            if (!isset($columns[$field])) {
+                continue;
+            }
+            if (is_bool($value)) {
+                $value = (int)$value; // prevent "false" problems
+            }
+            $cleaned[$field] = $value;
+        }
+
+        return $this->update_record_raw($table, $cleaned, $bulk);
+    }
+
+    /**
+     * Set a single field in every table row where the select statement evaluates to true.
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $newfield the field to set.
+     * @param string $newvalue the value to set the field to.
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @return bool success
+     */
+    public function set_field_select($table, $newfield, $newvalue, $select, array $params=null) {
+        if ($select) {
+            $select = "WHERE $select";
+        }
+        if (is_null($params)) {
+            $params = array();
+        }
+        list($select, $params, $type) = $this->fix_sql_params($select, $params);
+
+        if (is_bool($newvalue)) {
+            $newvalue = (int)$newvalue; // prevent "false" problems
+        }
+        if (is_null($newvalue)) {
+            $newfield = "$newfield = NULL";
+        } else {
+            $newfield = "$newfield = ?";
+            array_unshift($params, $newvalue);
+        }
+        $sql = "UPDATE {$this->prefix}$table SET $newfield $select";
+
+        if (!$rs = $this->db->Execute($sql, $params)) {
+            $this->report_error($sql, $params);
+            return false;
+        }
+        return true;
+    }
+
+
+    public function sql_cast_char2int($fieldname, $text=false) {
+        return ' CAST(' . $fieldname . ' AS SIGNED) ';
+    }
+
+}
Index: lib/xmldb/XMLDBConstants.php
===================================================================
RCS file: lib/xmldb/XMLDBConstants.php
diff -N lib/xmldb/XMLDBConstants.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/xmldb/XMLDBConstants.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,74 @@
+<?php // $Id: XMLDBConstants.php,v 1.5 2007/10/10 05:25:14 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This file contains all the constants and variables used
+/// by the XMLDB interface
+
+/// First, some constants to be used by actions
+    define('ACTION_NONE',             0);  //Default flags for class
+    define('ACTION_GENERATE_HTML',    1);  //The invoke function will return HTML
+    define('ACTION_GENERATE_XML',     2);  //The invoke function will return HTML
+    define('ACTION_HAVE_SUBACTIONS',  1);  //The class can have subaction
+
+/// Now the allowed DB Field Types
+    define ('XMLDB_TYPE_INCORRECT',   0);  //Wrong DB Type
+    define ('XMLDB_TYPE_INTEGER',     1);  //Integer
+    define ('XMLDB_TYPE_NUMBER',      2);  //Decimal number
+    define ('XMLDB_TYPE_FLOAT',       3);  //Floating Point number
+    define ('XMLDB_TYPE_CHAR',        4);  //String
+    define ('XMLDB_TYPE_TEXT',        5);  //Text
+    define ('XMLDB_TYPE_BINARY',      6);  //Binary
+    define ('XMLDB_TYPE_DATETIME',    7);  //Datetime
+    define ('XMLDB_TYPE_TIMESTAMP',   8);  //Timestamp
+
+/// Now the allowed DB Keys
+    define ('XMLDB_KEY_INCORRECT',     0);  //Wrong DB Key
+    define ('XMLDB_KEY_PRIMARY',       1);  //Primary Keys
+    define ('XMLDB_KEY_UNIQUE',        2);  //Unique Keys
+    define ('XMLDB_KEY_FOREIGN',       3);  //Foreign Keys
+    define ('XMLDB_KEY_CHECK',         4);  //Check Constraints - NOT USED!
+    define ('XMLDB_KEY_FOREIGN_UNIQUE',5);  //Foreign Key + Unique Key
+
+/// Now the allowed Statement Types
+    define ('XMLDB_STATEMENT_INCORRECT',   0);  //Wrong Statement Type
+    define ('XMLDB_STATEMENT_INSERT',      1);  //Insert Statements
+    define ('XMLDB_STATEMENT_UPDATE',      2);  //Update Statements
+    define ('XMLDB_STATEMENT_DELETE',      3);  //Delete Statements
+    define ('XMLDB_STATEMENT_CUSTOM',      4);  //Custom Statements
+
+/// Some other useful Constants
+    define ('XMLDB_UNSIGNED',        true);  //If the field is going to be unsigned
+    define ('XMLDB_NOTNULL',         true);  //If the field is going to be not null
+    define ('XMLDB_SEQUENCE',        true);  //If the field is going to be a sequence
+    define ('XMLDB_ENUM',            true);  //If the field is going to be a enumeration of possible fields
+    define ('XMLDB_INDEX_UNIQUE',    true);  //If the index is going to be unique
+    define ('XMLDB_INDEX_NOTUNIQUE',false);  //If the index is NOT going to be unique
+
+/// Some strings used widely
+    define ('XMLDB_LINEFEED', "\n");
+    define ('XMLDB_PHP_HEADER', '    if ($result && $oldversion < XXXXXXXXXX) {' . XMLDB_LINEFEED);
+    define ('XMLDB_PHP_FOOTER', '    }' . XMLDB_LINEFEED);
+?>
Index: lib/dml/adodb_moodle_database.php
===================================================================
RCS file: lib/dml/adodb_moodle_database.php
diff -N lib/dml/adodb_moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/adodb_moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,454 @@
+<?php  //$Id:$
+
+require_once($CFG->libdir.'/adodb/adodb.inc.php');
+require_once($CFG->libdir.'/dml/moodle_database.php');
+require_once($CFG->libdir.'/dml/adodb_moodle_recordset.php');
+
+/**
+ * Abstract moodle database class
+ * @package dmlib
+ */
+abstract class adodb_moodle_database extends moodle_database {
+
+    protected $db;
+    protected $columns = array(); // I wish we had a shared memory cache for this :-(
+
+    public function __construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        parent::__construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix);
+    }
+
+    public function connect() {
+        $this->db = ADONewConnection($this->get_dbtype());
+
+        global $db; $db = $this->db; // TODO: BC only for now
+
+        // See MDL-6760 for why this is necessary. In Moodle 1.8, once we start using NULLs properly,
+        // we probably want to change this value to ''.
+        $this->db->null2null = 'A long random string that will never, ever match something we want to insert into the database, I hope. \'';
+
+        if (!isset($this->dbpersist) or !empty($this->dbpersist)) {    // Use persistent connection (default)
+            if (!$this->db->PConnect($this->dbhost, $this->dbuser, $this->dbpass, $this->dbname)) {
+                return false;
+            }
+        } else {                                                     // Use single connection
+            if (!$this->db->Connect($this->dbhost, $this->dbuser, $this->dbpass, $this->dbname)) {
+                return false;
+            }
+        }
+        $this->configure_dbconnection();
+        return true;
+    }
+
+    protected function configure_dbconnection() {
+        // empty
+    }
+
+    /**
+     * Returns database server info array
+     * @return array
+     */
+    public function get_server_info() {
+        return $this->db->ServerInfo();
+    }
+
+    /**
+     * Return tables in database with WITHOUT current prefix
+     * @return array of table names in lowercase and without prefix
+     */
+    public function get_tables() {
+        $metatables = $this->db->MetaTables();
+        $tables = array();
+        foreach ($metatables as $table) {
+            $table = strtolower($table);
+            if (strpos($table, $this->prefix) === 0) {
+                $tablename = substr($table, strlen($this->prefix));
+                $tables[$tablename] = $tablename;
+            }
+        }
+        return $tables;
+    }
+
+    /**
+     * Return table indexes
+     * @return array of arrays
+     */
+    public function get_indexes($table) {
+        if (!$indexes = $this->db->MetaIndexes($this->prefix.$table)) {
+            return array();
+        }
+        $indexes = array_change_key_case($indexes, CASE_LOWER);
+        foreach ($indexes as $indexname => $index) {
+            $columns = $index['columns'];
+            /// column names always lowercase
+            $columns = array_map('strtolower', $columns);
+            $indexes[$indexname]['columns'] = $columns;
+        }
+
+        return $indexes;
+    }
+
+    public function get_columns($table) {
+        if (isset($this->columns[$table])) {
+            return $this->columns[$table];
+        }
+
+        if (!$columns = $this->db->MetaColumns($this->prefix.$table)) {
+            return array();
+        }
+
+        $this->columns[$table] = array();
+
+        foreach ($columns as $column) {
+            // colum names must be lowercase
+            $column->meta_type = substr($this->db->MetaType($column), 0 ,1); // only 1 character
+            $this->columns[$table][$column->name] = new database_column_info($column);
+        }
+
+        return $this->columns[$table];
+    }
+
+    public function reset_columns($table=null) {
+        if ($table) {
+            unset($this->columns[$table]);
+        } else {
+            $this->columns[$table] = array();
+        }
+    }
+
+    public function get_last_error() {
+        return $this->db->ErrorMsg();
+    }
+
+    /**
+     * Enable/disable very detailed debugging
+     * @param bool $state
+     */
+    public function set_debug($state) {
+        $this->db->debug = $state;
+    }
+
+    /**
+     * Returns debug status
+     * @return bool $state
+     */
+    public function get_debug() {
+        return $this->db->debug;
+    }
+
+    /**
+     * Enable/disable detailed sql logging
+     * @param bool $state
+     */
+    public function set_logging($state) {
+        // TODO: adodb sql logging shares one table without prefix per db - this is no longer acceptable :-(
+        // we must create one table shared by all drivers
+    }
+
+    /**
+     * Do NOT use in code, to be used by database_manager only!
+     * @param string $sql query
+     * @return bool success
+     */
+    public function change_database_structure($sql) {
+        if ($rs = $this->db->Execute($sql)) {
+            $result = true;
+        } else {
+            $result = false;
+            $this->report_error($sql);
+        }
+        return $result;
+    }
+
+    /**
+     * Execute general sql query. Should be used only when no other method suitable.
+     * Do NOT use this to make changes in db structure, use database_manager::execute_sql() instead!
+     * @param string $sql query
+     * @param array $params query parameters
+     * @return bool success
+     */
+    public function execute($sql, array $params=null) {
+
+        list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+
+        if (strpos($sql, ';') !== false) {
+            debugging('Error: Multiple sql statements found or bound parameters not used properly in query!');
+            return false;
+        }
+
+        if ($rs = $this->db->Execute($sql, $params)) {
+            $result = true;
+            $rs->Close();
+        } else {
+            $result = false;
+            $this->report_error($sql, $params);
+        }
+        return $result;
+    }
+
+    /**
+     * Insert new record into database, as fast as possible, no safety checks, lobs not supported.
+     * @param string $table name
+     * @param mixed $params data record as object or array
+     * @param bool $returnit return it of inserted record
+     * @param bool $bulk true means repeated inserts expected
+     * @return mixed success or new id
+     */
+    public function insert_record_raw($table, $params, $returnid=true, $bulk=false) {
+        if (!is_array($params)) {
+            $params = (array)$params;
+        }
+        unset($params['id']);
+
+        if (empty($params)) {
+            return false;
+        }
+
+        $fields = implode(',', array_keys($params));
+        $qms    = array_fill(0, count($params), '?');
+        $qms    = implode(',', $qms);
+
+        $sql = "INSERT INTO {$this->prefix}$table ($fields) VALUES($qms)";
+
+        if (!$rs = $this->db->Execute($sql, $params)) {
+            $this->report_error($sql, $params);
+            return false;
+        }
+        if (!$returnid) {
+            return true;
+        }
+        if ($id = $this->db->Insert_ID()) {
+            return (int)$id;
+        }
+        return false;
+    }
+
+    /**
+     * Update record in database, as fast as possible, no safety checks, lobs not supported.
+     * @param string $table name
+     * @param mixed $params data record as object or array
+     * @param bool true means repeated updates expected
+     * @return bool success
+     */
+    public function update_record_raw($table, $params, $bulk=false) {
+        if (!is_array($params)) {
+            $params = (array)$params;
+        }
+        if (!isset($params['id'])) {
+            return false;
+        }
+        $id = $params['id'];
+        unset($params['id']);
+
+        if (empty($params)) {
+            return false;
+        }
+
+        $sets = array();
+        foreach ($params as $field=>$value) {
+            $sets[] = "$field = ?";
+        }
+
+        $params[] = $id; // last ? in WHERE condition
+
+        $sets = implode(',', $sets);
+        $sql = "UPDATE {$this->prefix}$table SET $sets WHERE id=?";
+
+        if (!$rs = $this->db->Execute($sql, $params)) {
+            $this->report_error($sql, $params);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Delete one or more records from a table
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call (used to define the selection criteria).
+     * @param array $params array of sql parameters
+     * @return returns success.
+     */
+    public function delete_records_select($table, $select, array $params=null) {
+        if ($select) {
+            $select = "WHERE $select";
+        }
+        $sql = "DELETE FROM {$this->prefix}$table $select";
+
+        list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+
+        $result = false;
+        if ($rs = $this->db->Execute($sql, $params)) {
+            $result = true;
+            $rs->Close();
+        } else {
+            $this-report_error($sql, $params);
+        }
+        return $result;
+    }
+
+    /**
+     * Get a number of records as an moodle_recordset.  $sql must be a complete SQL query.
+     * Since this method is a little less readable, use of it should be restricted to
+     * code where it's possible there might be large datasets being returned.  For known
+     * small datasets use get_records_sql - it leads to simpler code.
+     *
+     * The return type is as for @see function get_recordset.
+     *
+     * @param string $sql the SQL select query to execute.
+     * @param array $params array of sql parameters
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an moodle_recorset object, or false if an error occured.
+     */
+    public function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0) {
+        list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+
+        if ($limitfrom || $limitnum) {
+            ///Special case, 0 must be -1 for ADOdb
+            $limitfrom = empty($limitfrom) ? -1 : $limitfrom;
+            $limitnum  = empty($limitnum) ? -1 : $limitnum;
+            $rs = $this->db->SelectLimit($sql, $limitnum, $limitfrom, $params);
+        } else {
+            $rs = $this->db->Execute($sql, $params);
+        }
+        if (!$rs) {
+            $this->report_error($sql, $params);
+            return false;
+        }
+
+        return $this->create_recordset($rs);
+    }
+
+    protected function create_recordset($rs) {
+        return new adodb_moodle_recordset($rs);
+    }
+
+    /**
+     * Get a number of records as an array of objects.
+     *
+     * Return value as for @see function get_records.
+     *
+     * @param string $sql the SQL select query to execute. The first column of this SELECT statement
+     *   must be a unique value (usually the 'id' field), as it will be used as the key of the
+     *   returned array.
+     * @param array $params array of sql parameters
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an array of objects, or empty array if no records were found, or false if an error occured.
+     */
+    public function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnum=0) {
+        list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+        if ($limitfrom || $limitnum) {
+            ///Special case, 0 must be -1 for ADOdb
+            $limitfrom = empty($limitfrom) ? -1 : $limitfrom;
+            $limitnum  = empty($limitnum) ? -1 : $limitnum;
+            $rs = $this->db->SelectLimit($sql, $limitnum, $limitfrom, $params);
+        } else {
+            $rs = $this->db->Execute($sql, $params);
+        }
+        if (!$rs) {
+            $this->report_error($sql, $params);
+            return false;
+        }
+        $return = $this->adodb_recordset_to_array($rs);
+        $rs->close();
+        return $return;
+    }
+
+    /**
+     * Selects rows and return values of first column as array.
+     *
+     * @param string $sql The SQL query
+     * @param array $params array of sql parameters
+     * @return mixed array of values or false if an error occured
+     */
+    public function get_fieldset_sql($sql, array $params=null) {
+        list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
+        if (!$rs = $this->db->Execute($sql, $params)) {
+            $this->report_error($sql, $params);
+            return false;
+        }
+        $results = array();
+        while (!$rs->EOF) {
+            $res = reset($rs->fields);
+            $results[] = $res;
+            $rs->MoveNext();
+        }
+        $rs->Close();
+        return $results;
+    }
+
+    protected function adodb_recordset_to_array($rs) {
+        $debugging = debugging('', DEBUG_DEVELOPER);
+
+        if ($rs->EOF) {
+            // BIIIG change here - return empty array() if nothing found (2.0)
+            return array();
+        }
+
+        $objects = array();
+    /// First of all, we are going to get the name of the first column
+    /// to introduce it back after transforming the recordset to assoc array
+    /// See http://docs.moodle.org/en/XMLDB_Problems, fetch mode problem.
+        $firstcolumn = $rs->FetchField(0);
+    /// Get the whole associative array
+        if ($records = $rs->GetAssoc(true)) {
+            foreach ($records as $key => $record) {
+                $record = array($firstcolumn->name=>$key) + $record; /// Re-add the assoc field  (as FIRST element since 2.0)
+                if ($debugging && array_key_exists($key, $objects)) {
+                    debugging("Did you remember to make the first column something unique in your call to get_records? Duplicate value '$key' found in column '".$firstcolumn->name."'.", DEBUG_DEVELOPER);
+                }
+                $objects[$key] = (object) $record; /// To object
+            }
+            return $objects;
+    /// Fallback in case we only have 1 field in the recordset. MDL-5877
+        } else if ($rs->_numOfFields == 1 and $records = $rs->GetRows()) {
+            foreach ($records as $key => $record) {
+                if ($debugging && array_key_exists($record[$firstcolumn->name], $objects)) {
+                    debugging("Did you remember to make the first column something unique in your call to get_records? Duplicate value '".$record[$firstcolumn->name]."' found in column '".$firstcolumn->name."'.", DEBUG_DEVELOPER);
+                }
+                $objects[$record[$firstcolumn->name]] = (object) $record; /// The key is the first column value (like Assoc)
+            }
+            return $objects;
+        } else {
+            // weird error?
+            return false;
+        }
+    }
+
+    public function sql_substr() {
+        return $this->db->substr;
+    }
+
+    public function sql_concat() {
+        $args = func_get_args();
+        return call_user_func_array(array($this->db, 'Concat'), $args);
+    }
+
+    public function sql_concat_join($separator="' '", $elements=array()) {
+        // Intersperse $elements in the array.
+        // Add items to the array on the fly, walking it
+        // _backwards_ splicing the elements in. The loop definition
+        // should skip first and last positions.
+        for ($n=count($elements)-1; $n > 0 ; $n--) {
+            array_splice($elements, $n, 0, $separator);
+        }
+        return call_user_func_array(array($this->db, 'Concat'), $elements);
+    }
+
+
+
+    public function begin_sql() {
+        $this->db->BeginTrans();
+        return true;
+    }
+    public function commit_sql() {
+        $this->db->CommitTrans();
+        return true;
+    }
+    public function rollback_sql() {
+        $this->db->RollbackTrans();
+        return true;
+    }
+
+}
Index: lib/xmldb/XMLDBField.class.php
===================================================================
RCS file: lib/xmldb/XMLDBField.class.php
diff -N lib/xmldb/XMLDBField.class.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/xmldb/XMLDBField.class.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,912 @@
+<?php // $Id: XMLDBField.class.php,v 1.14 2008/01/02 16:49:11 stronk7 Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represent one XMLDB Field
+
+class XMLDBField extends XMLDBObject {
+
+    var $type;
+    var $length;
+    var $unsigned;
+    var $notnull;
+    var $default;
+    var $sequence;
+    var $enum;
+    var $enumvalues;
+    var $decimals;
+
+    /**
+     * Creates one new XMLDBField
+     */
+    function XMLDBField($name) {
+        parent::XMLDBObject($name);
+        $this->type = NULL;
+        $this->length = NULL;
+        $this->unsigned = true;
+        $this->notnull = false;
+        $this->default = NULL;
+        $this->sequence = false;
+        $this->enum = false;
+        $this->enumvalues = NULL;
+        $this->decimals = NULL;
+    }
+
+    /**
+     * Set all the attributes of one XMLDBField
+     *
+     * @param string type XMLDB_TYPE_INTEGER, XMLDB_TYPE_NUMBER, XMLDB_TYPE_CHAR, XMLDB_TYPE_TEXT, XMLDB_TYPE_BINARY
+     * @param string precision length for integers and chars, two-comma separated numbers for numbers and 'small', 'medium', 'big' for texts and binaries
+     * @param string unsigned XMLDB_UNSIGNED or null (or false)
+     * @param string notnull XMLDB_NOTNULL or null (or false)
+     * @param string sequence XMLDB_SEQUENCE or null (or false)
+     * @param string enum XMLDB_ENUM or null (or false)
+     * @param array enumvalues an array of possible values if XMLDB_ENUM is set
+     * @param string default meaningful default o null (or false)
+     */
+    function setAttributes($type, $precision=null, $unsigned=null, $notnull=null, $sequence=null, $enum=null, $enumvalues=null, $default=null, $previous=null) {
+        $this->type = $type;
+    /// Try to split the precision into length and decimals and apply
+    /// each one as needed
+        $precisionarr = explode(',', $precision);
+        if (isset($precisionarr[0])) {
+            $this->length = trim($precisionarr[0]);
+        }
+        if (isset($precisionarr[1])) {
+            $this->decimals = trim($precisionarr[1]);
+        }
+        $this->precision = $type;
+        $this->unsigned = !empty($unsigned) ? true : false;
+        $this->notnull = !empty($notnull) ? true : false;
+        $this->sequence = !empty($sequence) ? true : false;
+        $this->enum = !empty($enum) ? true : false;
+    /// Accept both quoted and non-quoted vales (quoting them)a
+        if (is_array($enumvalues)) {
+            $this->enumvalues = array();
+            foreach ($enumvalues as $value) {
+            /// trim each value quotes
+                $value = trim($value, "'");
+            /// add them back
+                $value = "'" . $value . "'";
+                $this->enumvalues[] = $value;
+            }
+        }
+        $this->setDefault($default);
+
+        $this->previous = $previous;
+    }
+
+    /**
+     * Get the type
+     */
+    function getType() {
+        return $this->type;
+    }
+
+    /**
+     * Get the length
+     */
+    function getLength() {
+        return $this->length;
+    }
+
+    /**
+     * Get the decimals
+     */
+    function getDecimals() {
+        return $this->decimals;
+    }
+
+    /**
+     * Get the notnull
+     */
+    function getNotNull() {
+        return $this->notnull;
+    }
+
+    /**
+     * Get the unsigned
+     */
+    function getUnsigned() {
+        return $this->unsigned;
+    }
+
+    /**
+     * Get the sequence
+     */
+    function getSequence() {
+        return $this->sequence;
+    }
+
+    /**
+     * Get the enum
+     */
+    function getEnum() {
+        return $this->enum;
+    }
+
+    /**
+     * Get the enumvalues
+     */
+    function getEnumValues() {
+        return $this->enumvalues;
+    }
+
+    /**
+     * Get the default
+     */
+    function getDefault() {
+        return $this->default;
+    }
+
+    /**
+     * Set the field type
+     */
+    function setType($type) {
+        $this->type = $type;
+    }
+
+    /**
+     * Set the field length
+     */
+    function setLength($length) {
+        $this->length = $length;
+    }
+
+    /**
+     * Set the field decimals
+     */
+    function setDecimals($decimals) {
+        $this->decimals = $decimals;
+    }
+
+    /**
+     * Set the field unsigned
+     */
+    function setUnsigned($unsigned=true) {
+        $this->unsigned = $unsigned;
+    }
+
+    /**
+     * Set the field notnull
+     */
+    function setNotNull($notnull=true) {
+        $this->notnull = $notnull;
+    }
+
+    /**
+     * Set the field sequence
+     */
+    function setSequence($sequence=true) {
+        $this->sequence = $sequence;
+    }
+
+    /**
+     * Set the field enum
+     */
+    function setEnum($enum=true) {
+        $this->enum = $enum;
+    }
+
+    /**
+     * Set the field enumvalues, quoting unquoted values
+     */
+    function setEnumValues($enumvalues) {
+        if (is_array($enumvalues)) {
+            $this->enumvalues = array();
+            foreach ($enumvalues as $value) {
+            /// trim each value quotes
+                $value = trim($value, "'");
+            /// add them back
+                $value = "'" . $value . "'";
+                $this->enumvalues[] = $value;
+            }
+        }
+    }
+
+    /**
+     * Set the field default
+     */
+    function setDefault($default) {
+    /// Check, warn and auto-fix '' (empty) defaults for CHAR NOT NULL columns, changing them
+    /// to NULL so XMLDB will apply the proper default
+        if ($this->type == XMLDB_TYPE_CHAR && $this->notnull && $default === '') {
+            $this->errormsg = 'XMLDB has detected one CHAR NOT NULL column (' . $this->name . ") with '' (empty string) as DEFAULT value. This type of columns must have one meaningful DEFAULT declared or none (NULL). XMLDB have fixed it automatically changing it to none (NULL). The process will continue ok and proper defaults will be created accordingly with each DB requirements. Please fix it in source (XML and/or upgrade script) to avoid this message to be displayed.";
+            $this->debug($this->errormsg);
+            $default = NULL;
+        }
+        $this->default = $default;
+    }
+
+    /**
+     * Load data from XML to the table
+     */
+    function arr2XMLDBField($xmlarr) {
+
+        $result = true;
+
+    /// Debug the table
+    /// traverse_xmlize($xmlarr);                   //Debug
+    /// print_object ($GLOBALS['traverse_array']);  //Debug
+    /// $GLOBALS['traverse_array']="";              //Debug
+
+    /// Process table attributes (name, type, length, unsigned,
+    /// notnull, sequence, enum, enumvalues, decimals, comment,
+    /// previous, next)
+        if (isset($xmlarr['@']['NAME'])) {
+            $this->name = trim($xmlarr['@']['NAME']);
+        } else {
+            $this->errormsg = 'Missing NAME attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+        if (isset($xmlarr['@']['TYPE'])) {
+        /// Check for valid type
+            $type = $this->getXMLDBFieldType(trim($xmlarr['@']['TYPE']));
+            if ($type) {
+                $this->type = $type;
+            } else {
+                $this->errormsg = 'Invalid TYPE attribute';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        } else {
+            $this->errormsg = 'Missing TYPE attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+        if (isset($xmlarr['@']['LENGTH'])) {
+            $length = trim($xmlarr['@']['LENGTH']);
+        /// Check for integer values
+            if ($this->type == XMLDB_TYPE_INTEGER ||
+                $this->type == XMLDB_TYPE_NUMBER ||
+                $this->type == XMLDB_TYPE_CHAR) {
+                if (!(is_numeric($length)&&(intval($length)==floatval($length)))) {
+                    $this->errormsg = 'Incorrect LENGTH attribute for int, number or char fields';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                } else if (!$length) {
+                    $this->errormsg = 'Zero LENGTH attribute';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            }
+        /// Check for big, medium, small to be applied to text and binary
+            if ($this->type == XMLDB_TYPE_TEXT ||
+                $this->type == XMLDB_TYPE_BINARY) {
+                if (!$length) {
+                    $length == 'big';
+                }
+                if ($length != 'big' &&
+                    $length != 'medium' &&
+                    $length != 'small') {
+                    $this->errormsg = 'Incorrect LENGTH attribute for text and binary fields (only big, medium and small allowed)';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            }
+        /// Finally, set the length
+            $this->length = $length;
+        }
+
+        if (isset($xmlarr['@']['UNSIGNED'])) {
+            $unsigned = strtolower(trim($xmlarr['@']['UNSIGNED']));
+            if ($unsigned == 'true') {
+                $this->unsigned = true;
+            } else if ($unsigned == 'false') {
+                $this->unsigned = false;
+            } else {
+                $this->errormsg = 'Incorrect UNSIGNED attribute (true/false allowed)';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        }
+
+        if (isset($xmlarr['@']['NOTNULL'])) {
+            $notnull = strtolower(trim($xmlarr['@']['NOTNULL']));
+            if ($notnull == 'true') {
+                $this->notnull = true;
+            } else if ($notnull == 'false') {
+                $this->notnull = false;
+            } else {
+                $this->errormsg = 'Incorrect NOTNULL attribute (true/false allowed)';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        }
+
+        if (isset($xmlarr['@']['SEQUENCE'])) {
+            $sequence = strtolower(trim($xmlarr['@']['SEQUENCE']));
+            if ($sequence == 'true') {
+                $this->sequence = true;
+            } else if ($sequence == 'false') {
+                $this->sequence = false;
+            } else {
+                $this->errormsg = 'Incorrect SEQUENCE attribute (true/false allowed)';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        }
+
+        if (isset($xmlarr['@']['DEFAULT'])) {
+            $this->setDefault(trim($xmlarr['@']['DEFAULT']));
+        }
+
+        if (isset($xmlarr['@']['ENUM'])) {
+            $enum = strtolower(trim($xmlarr['@']['ENUM']));
+            if ($enum == 'true') {
+                $this->enum = true;
+            } else if ($enum == 'false') {
+                $this->enum = false;
+            } else {
+                $this->errormsg = 'Incorrect ENUM attribute (true/false allowed)';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        }
+
+        if (isset($xmlarr['@']['ENUMVALUES'])) {
+            $enumvalues = trim($xmlarr['@']['ENUMVALUES']);
+            if (!$this->enum) {
+                $this->errormsg = 'Wrong ENUMVALUES attribute (not ENUM)';
+                $this->debug($this->errormsg);
+                $result = false;
+                $this->enumvalues = $enumvalues;
+            } else {
+            /// Check we have a valid list (comma separated of quoted values)
+                $enumarr = explode(',',$enumvalues);
+                if ($enumarr) {
+                    foreach ($enumarr as $key => $enumelement) {
+                    /// Clear some spaces
+                        $enumarr[$key] = trim($enumelement);
+                        $enumelement = trim($enumelement);
+                    /// Skip if under error
+                        if (!$result) {
+                            continue;
+                        }
+                    /// Look for quoted strings
+                        if (substr($enumelement, 0, 1) != "'" ||
+                            substr($enumelement, -1, 1) != "'") {
+                            $this->errormsg = 'Incorrect ENUMVALUES attribute (some value is not properly quoted)';
+                            $this->debug($this->errormsg);
+                            $result = false;
+                        }
+                    }
+                } else {
+                    $this->errormsg = 'Incorrect ENUMVALUES attribute (comma separated of quoted values)';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            }
+        } else if ($this->enum) {
+            $this->errormsg = 'Incorrect ENUMVALUES attribute (field is not declared as ENUM)';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+    /// Finally, set the value
+        if ($this->enum) {
+            $this->enumvalues = $enumarr;
+        }
+
+        $decimals = NULL;
+        if (isset($xmlarr['@']['DECIMALS'])) {
+            $decimals = trim($xmlarr['@']['DECIMALS']);
+        /// Check for integer values
+            if ($this->type == XMLDB_TYPE_NUMBER ||
+                $this->type == XMLDB_TYPE_FLOAT) {
+                if (!(is_numeric($decimals)&&(intval($decimals)==floatval($decimals)))) {
+                    $this->errormsg = 'Incorrect DECIMALS attribute for number field';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                } else if ($this->length <= $decimals){
+                    $this->errormsg = 'Incorrect DECIMALS attribute (bigget than length)';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            } else {
+                $this->errormsg = 'Incorrect DECIMALS attribute for non-number field';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        } else {
+            if ($this->type == XMLDB_TYPE_NUMBER) {
+                $decimals = 0;
+            }
+        }
+     // Finally, set the decimals
+        if ($this->type == XMLDB_TYPE_NUMBER ||
+            $this->type == XMLDB_TYPE_FLOAT) {
+            $this->decimals = $decimals;
+        }
+
+        if (isset($xmlarr['@']['COMMENT'])) {
+            $this->comment = trim($xmlarr['@']['COMMENT']);
+        }
+
+        if (isset($xmlarr['@']['PREVIOUS'])) {
+            $this->previous = trim($xmlarr['@']['PREVIOUS']);
+        }
+
+        if (isset($xmlarr['@']['NEXT'])) {
+            $this->next = trim($xmlarr['@']['NEXT']);
+        }
+
+    /// Set some attributes
+        if ($result) {
+            $this->loaded = true;
+        }
+        $this->calculateHash();
+        return $result;
+    }
+
+    /**
+     * This function returns the correct XMLDB_TYPE_XXX value for the
+     * string passed as argument
+     */
+    function getXMLDBFieldType($type) {
+
+        $result = XMLDB_TYPE_INCORRECT;
+
+        switch (strtolower($type)) {
+            case 'int':
+                $result = XMLDB_TYPE_INTEGER;
+                break;
+            case 'number':
+                $result = XMLDB_TYPE_NUMBER;
+                break;
+            case 'float':
+                $result = XMLDB_TYPE_FLOAT;
+                break;
+            case 'char':
+                $result = XMLDB_TYPE_CHAR;
+                break;
+            case 'text':
+                $result = XMLDB_TYPE_TEXT;
+                break;
+            case 'binary':
+                $result = XMLDB_TYPE_BINARY;
+                break;
+            case 'datetime':
+                $result = XMLDB_TYPE_DATETIME;
+                break;
+        }
+    /// Return the normalized XMLDB_TYPE
+        return $result;
+    }
+
+    /**
+     * This function returns the correct name value for the
+     * XMLDB_TYPE_XXX passed as argument
+     */
+    function getXMLDBTypeName($type) {
+
+        $result = "";
+
+        switch (strtolower($type)) {
+            case XMLDB_TYPE_INTEGER:
+                $result = 'int';
+                break;
+            case XMLDB_TYPE_NUMBER:
+                $result = 'number';
+                break;
+            case XMLDB_TYPE_FLOAT:
+                $result = 'float';
+                break;
+            case XMLDB_TYPE_CHAR:
+                $result = 'char';
+                break;
+            case XMLDB_TYPE_TEXT:
+                $result = 'text';
+                break;
+            case XMLDB_TYPE_BINARY:
+                $result = 'binary';
+                break;
+            case XMLDB_TYPE_DATETIME:
+                $result = 'datetime';
+                break;
+        }
+    /// Return the normalized name
+        return $result;
+    }
+
+    /**
+     * This function calculate and set the hash of one XMLDBField
+     */
+     function calculateHash($recursive = false) {
+        if (!$this->loaded) {
+            $this->hash = NULL;
+        } else {
+            $key = $this->name . $this->type . $this->length .
+                   $this->unsigned . $this->notnull . $this->sequence .
+                   $this->decimals . $this->comment;
+            if ($this->enum) {
+                $key .= implode(', ',$this->enumvalues);
+            }
+            $this->hash = md5($key);
+        }
+    }
+
+    /**
+     *This function will output the XML text for one field
+     */
+    function xmlOutput() {
+        $o = '';
+        $o.= '        <FIELD NAME="' . $this->name . '"';
+        $o.= ' TYPE="' . $this->getXMLDBTypeName($this->type) . '"';
+        if ($this->length) {
+            $o.= ' LENGTH="' . $this->length . '"';
+        }
+        if ($this->notnull) {
+            $notnull = 'true';
+        } else {
+            $notnull = 'false';
+        }
+        $o.= ' NOTNULL="' . $notnull . '"';
+        if ($this->unsigned) {
+            $unsigned = 'true';
+        } else {
+            $unsigned = 'false';
+        }
+        if ($this->type == XMLDB_TYPE_INTEGER ||
+            $this->type == XMLDB_TYPE_NUMBER ||
+            $this->type == XMLDB_TYPE_FLOAT) {
+            if ($this->unsigned) {
+                $unsigned = 'true';
+            } else {
+                $unsigned = 'false';
+            }
+            $o.= ' UNSIGNED="' . $unsigned . '"';
+        }
+        if (!$this->sequence && $this->default !== NULL) {
+            $o.= ' DEFAULT="' . $this->default . '"';
+        }
+        if ($this->sequence) {
+            $sequence = 'true';
+        } else {
+            $sequence = 'false';
+        }
+        $o.= ' SEQUENCE="' . $sequence . '"';
+        if ($this->enum) {
+            $enum = 'true';
+        } else {
+            $enum = 'false';
+        }
+        $o.= ' ENUM="' . $enum . '"';
+        if ($this->enum) {
+            $o.= ' ENUMVALUES="' . implode(', ', $this->enumvalues) . '"';
+        }
+        if ($this->decimals !== NULL) {
+            $o.= ' DECIMALS="' . $this->decimals . '"';
+        }
+        if ($this->comment) {
+            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
+        }
+        if ($this->previous) {
+            $o.= ' PREVIOUS="' . $this->previous . '"';
+        }
+        if ($this->next) {
+            $o.= ' NEXT="' . $this->next . '"';
+        }
+        $o.= '/>' . "\n";
+
+        return $o;
+    }
+
+    /**
+     * This function will set all the attributes of the XMLDBField object
+     * based on information passed in one ADOField
+     */
+    function setFromADOField($adofield) {
+
+    /// Calculate the XMLDB_TYPE
+        switch (strtolower($adofield->type)) {
+            case 'int':
+            case 'tinyint':
+            case 'smallint':
+            case 'bigint':
+            case 'integer':
+                $this->type = XMLDB_TYPE_INTEGER;
+                break;
+            case 'number':
+            case 'decimal':
+            case 'dec':
+            case 'numeric':
+                $this->type = XMLDB_TYPE_NUMBER;
+                break;
+            case 'float':
+            case 'double':
+                $this->type = XMLDB_TYPE_FLOAT;
+                break;
+            case 'char':
+            case 'varchar':
+            case 'enum':
+                $this->type = XMLDB_TYPE_CHAR;
+                break;
+            case 'text':
+            case 'tinytext':
+            case 'mediumtext':
+            case 'longtext':
+                $this->type = XMLDB_TYPE_TEXT;
+                break;
+            case 'blob':
+            case 'tinyblob':
+            case 'mediumblob':
+            case 'longblob':
+                $this->type = XMLDB_TYPE_BINARY;
+                break;
+            case 'datetime':
+            case 'timestamp':
+                $this->type = XMLDB_TYPE_DATETIME;
+                break;
+            default:
+                $this->type = XMLDB_TYPE_TEXT;
+        }
+    /// Calculate the length of the field
+        if ($adofield->max_length > 0 &&
+               ($this->type == XMLDB_TYPE_INTEGER ||
+                $this->type == XMLDB_TYPE_NUMBER  ||
+                $this->type == XMLDB_TYPE_FLOAT   ||
+                $this->type == XMLDB_TYPE_CHAR)) {
+            $this->length = $adofield->max_length;
+        }
+        if ($this->type == XMLDB_TYPE_TEXT) {
+            switch (strtolower($adofield->type)) {
+                case 'tinytext':
+                case 'text':
+                    $this->length = 'small';
+                    break;
+                case 'mediumtext':
+                    $this->length = 'medium';
+                    break;
+                case 'longtext':
+                    $this->length = 'big';
+                    break;
+                default:
+                    $this->length = 'small';
+            }
+        }
+        if ($this->type == XMLDB_TYPE_BINARY) {
+            switch (strtolower($adofield->type)) {
+                case 'tinyblob':
+                case 'blob':
+                    $this->length = 'small';
+                    break;
+                case 'mediumblob':
+                    $this->length = 'medium';
+                    break;
+                case 'longblob':
+                    $this->length = 'big';
+                    break;
+                default:
+                    $this->length = 'small';
+            }
+        }
+    /// Calculate the decimals of the field
+        if ($adofield->max_length > 0 &&
+            $adofield->scale &&
+               ($this->type == XMLDB_TYPE_NUMBER ||
+                $this->type == XMLDB_TYPE_FLOAT)) {
+            $this->decimals = $adofield->scale;
+        }
+    /// Calculate the unsigned field
+        if ($adofield->unsigned &&
+               ($this->type == XMLDB_TYPE_INTEGER ||
+                $this->type == XMLDB_TYPE_NUMBER  ||
+                $this->type == XMLDB_TYPE_FLOAT)) {
+            $this->unsigned = true;
+        }
+    /// Calculate the notnull field
+        if ($adofield->not_null) {
+            $this->notnull = true;
+        }
+    /// Calculate the default field
+        if ($adofield->has_default) {
+            $this->default = $adofield->default_value;
+        }
+    /// Calculate the sequence field
+        if ($adofield->auto_increment) {
+            $this->sequence = true;
+        /// Sequence fields are always unsigned
+            $this->unsigned = true;
+        }
+    /// Calculate the enum and enumvalues field
+        if ($adofield->type == 'enum') {
+            $this->enum = true;
+            $this->enumvalues = $adofield->enums;
+        }
+    /// Some more fields
+        $this->loaded = true;
+        $this->changed = true;
+    }
+
+    /**
+     * Returns the PHP code needed to define one XMLDBField
+     */
+    function getPHP($includeprevious=true) {
+
+        $result = '';
+
+    /// The XMLDBTYPE
+        switch ($this->getType()) {
+            case XMLDB_TYPE_INTEGER:
+                $result .= 'XMLDB_TYPE_INTEGER' . ', ';
+                break;
+            case XMLDB_TYPE_NUMBER:
+                $result .= 'XMLDB_TYPE_NUMBER' . ', ';
+                break;
+            case XMLDB_TYPE_FLOAT:
+                $result .= 'XMLDB_TYPE_FLOAT' . ', ';
+                break;
+            case XMLDB_TYPE_CHAR:
+                $result .= 'XMLDB_TYPE_CHAR' . ', ';
+                break;
+            case XMLDB_TYPE_TEXT:
+                $result .= 'XMLDB_TYPE_TEXT' . ', ';
+                break;
+            case XMLDB_TYPE_BINARY:
+                $result .= 'XMLDB_TYPE_BINARY' . ', ';
+                break;
+            case XMLDB_TYPE_DATETIME:
+                $result .= 'XMLDB_TYPE_DATETIME' . ', ';
+                break;
+            case XMLDB_TYPE_TIMESTAMP:
+                $result .= 'XMLDB_TYPE_TIMESTAMP' . ', ';
+                break;
+        }
+    /// The length
+        $length = $this->getLength();
+        $decimals = $this->getDecimals();
+        if (!empty($length)) {
+            $result .= "'" . $length;
+            if (!empty($decimals)) {
+                $result .= ', ' . $decimals;
+            }
+            $result .= "', ";
+        } else {
+            $result .= 'null, ';
+        }
+    /// Unsigned (only applicable to numbers)
+        $unsigned = $this->getUnsigned();
+        if (!empty($unsigned) &&
+           ($this->getType() == XMLDB_TYPE_INTEGER || $this->getType() == XMLDB_TYPE_NUMBER || $this->getType() == XMLDB_TYPE_FLOAT)) {
+            $result .= 'XMLDB_UNSIGNED' . ', ';
+        } else {
+            $result .= 'null, ';
+        }
+    /// Not Null
+        $notnull = $this->getNotnull();
+        if (!empty($notnull)) {
+            $result .= 'XMLDB_NOTNULL' . ', ';
+        } else {
+            $result .= 'null, ';
+        }
+    /// Sequence
+        $sequence = $this->getSequence();
+        if (!empty($sequence)) {
+            $result .= 'XMLDB_SEQUENCE' . ', ';
+        } else {
+            $result .= 'null, ';
+        }
+    /// Enum
+        $enum = $this->getEnum();
+        if (!empty($enum)) {
+            $result .= 'XMLDB_ENUM' . ', ';
+        } else {
+            $result .= 'null, ';
+        }
+    /// Enumvalues
+        $enumvalues = $this->getEnumValues();
+        if (!empty($enumvalues)) {
+            $result .= 'array(' . implode(', ', $enumvalues) . '), ';
+        } else {
+            $result .= 'null, ';
+        }
+    /// Default
+        $default =  $this->getDefault();
+        if ($default !== null && !$this->getSequence()) {
+            $result .= "'" . $default . "'";
+        } else {
+            $result .= 'null';
+        }
+    /// Previous (decided by parameter)
+        if ($includeprevious) {
+            $previous = $this->getPrevious();
+            if (!empty($previous)) {
+                $result .= ", '" . $previous . "'";
+            } else {
+                $result .= ', null';
+            }
+        }
+    /// Return result
+        return $result;
+    }
+
+    /**
+     * Shows info in a readable format
+     */
+    function readableInfo() {
+        $o = '';
+    /// type
+        $o .= $this->getXMLDBTypeName($this->type);
+    /// length
+        if ($this->type == XMLDB_TYPE_INTEGER ||
+            $this->type == XMLDB_TYPE_NUMBER  ||
+            $this->type == XMLDB_TYPE_FLOAT   ||
+            $this->type == XMLDB_TYPE_CHAR) {
+            if ($this->length) {
+                $o .= ' (' . $this->length;
+                if ($this->type == XMLDB_TYPE_NUMBER  ||
+                    $this->type == XMLDB_TYPE_FLOAT) {
+                    if ($this->decimals !== NULL) {
+                        $o .= ', ' . $this->decimals;
+                    }
+                }
+                $o .= ')';
+            }
+        }
+        if ($this->type == XMLDB_TYPE_TEXT ||
+            $this->type == XMLDB_TYPE_BINARY) {
+                $o .= ' (' . $this->length . ')';
+        }
+    /// enum
+        if ($this->enum) {
+            $o .= ' enum(' . implode(', ', $this->enumvalues) . ')';
+        }
+    /// unsigned
+        if ($this->type == XMLDB_TYPE_INTEGER ||
+            $this->type == XMLDB_TYPE_NUMBER ||
+            $this->type == XMLDB_TYPE_FLOAT) {
+            if ($this->unsigned) {
+                $o .= ' unsigned';
+            } else {
+                $o .= ' signed';
+            }
+        }
+    /// not null
+        if ($this->notnull) {
+            $o .= ' not null';
+        }
+    /// default
+        if ($this->default !== NULL) {
+            $o .= ' default ';
+            if ($this->type == XMLDB_TYPE_CHAR ||
+                $this->type == XMLDB_TYPE_TEXT) {
+                    $o .= "'" . $this->default . "'";
+            } else {
+                $o .= $this->default;
+            }
+        }
+    /// sequence
+        if ($this->sequence) {
+            $o .= ' auto-numbered';
+        }
+
+        return $o;
+    }
+}
+
+?>
Index: lib/ddl/database_manager.php
===================================================================
RCS file: lib/ddl/database_manager.php
diff -N lib/ddl/database_manager.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/ddl/database_manager.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1138 @@
+<?php // $Id: XMLDBGenerator.class.php,v 1.66 2007/10/10 05:25:25 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas     http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represent the base generator class where all the
+/// needed functions to generate proper SQL are defined.
+
+/// The rest of classes will inherit, by default, the same logic.
+/// Functions will be overriden as needed to generate correct SQL.
+
+class database_manager {
+
+    protected $mdb;
+    public $generator; // public because XMLDB editor needs to access it
+
+    /**
+     * Creates new database manager
+     * @param object moodle_database instance
+     */
+    public function __construct($mdb, $generator) {
+        global $CFG;
+
+        $this->mdb       = $mdb;
+        $this->generator = $generator;
+    }
+
+    /**
+     * This function will execute an array of SQL commands, returning
+     * true/false if any error is found and stopping/continue as desired.
+     * It's widely used by all the ddllib.php functions
+     *
+     * @param array $sqlarr array of sql statements to execute
+     * @param boolean $continue to specify if must continue on error (true) or stop (false)
+     * @param boolean $feedback to specify to show status info (true) or not (false)
+     * @param boolean true if everything was ok, false if some error was found
+     */
+    protected function execute_sql_arr(array $sqlarr, $continue, $feedback=true) {
+        $result = true;
+        foreach ($sqlarr as $sql) {
+            $result = $this->execute_sql($sql, $feedback) && $result;
+            if (!$continue and !$result) {
+                break;
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * Execute a given sql command string - used in upgrades
+     *
+     * Completely general function - it just runs some SQL and reports success.
+     *
+     * @param string $command The sql string you wish to be executed.
+     * @param bool $feedback Set this argument to true if the results generated should be printed. Default is true.
+     * @return bool success
+     */
+    protected function execute_sql($sql, $feedback=true) {
+        $result = $this->mdb->change_database_structure($sql);
+
+        if ($feedback and !$result) {
+            notify('<strong>' . get_string('error') . '</strong>');
+        }
+
+        $this->mdb->reset_columns();  // Clear out the cache, just in case changes were made to table structures
+
+        return $result;
+    }
+
+    /**
+     * Given one XMLDBTable, check if it exists in DB (true/false)
+     *
+     * @param mixed the table to be searched (string name or XMLDBTable instance)
+     * @return boolean true/false
+     */
+    public function table_exists($table) {
+    /// Do this function silenty (to avoid output in install/upgrade process)
+        $olddbdebug = $this->mdb->get_debug();
+        $this->mdb->set_debug(false);
+
+        if (is_string($table)) {
+            $tablename = $table;
+        } else {
+        /// Calculate the name of the table
+            $tablename = $table->getName();
+        }
+
+    /// get all tables in moodle database
+        $tables = $this->mdb->get_tables();
+        $exists = in_array($tablename, $tables);
+    /// Re-set original debug
+        $this->mdb->set_debug($olddbdebug);
+
+        return $exists;
+    }
+
+    /**
+     * Given one XMLDBField, check if it exists in DB (true/false)
+     *
+     * @param mixed the table to be searched (string name or XMLDBTable instance)
+     * @param mixed the field to be searched for (string name or XMLDBField instance)
+     * @return boolean true/false
+     */
+    public function field_exists($table, $field) {
+        $exists = true;
+
+    /// Check the table exists
+        if (!$this->table_exists($table)) {
+            return false;
+        }
+
+    /// Do this function silenty (to avoid output in install/upgrade process)
+        $olddbdebug = $this->mdb->get_debug();
+        $this->mdb->set_debug(false);
+
+        if (is_string($table)) {
+            $tablename = $table;
+        } else {
+        /// Calculate the name of the table
+            $tablename = $table->getName();
+        }
+
+        if (is_string($field)) {
+            $fieldname = $field;
+        } else {
+        /// Calculate the name of the table
+            $fieldname = $field->getName();
+        }
+
+    /// Get list of fields in table
+        $this->mdb->reset_columns($tablename); // better reset before testing
+        $columns = $this->mdb->get_columns($tablename);
+
+        $exists = array_key_exists($fieldname,  $columns);
+
+    /// Re-set original debug
+        $this->mdb->set_debug($olddbdebug);
+
+        return $exists;
+    }
+
+    /**
+     * Given one XMLDBIndex, the function returns the name of the index in DB (if exists)
+     * of false if it doesn't exist
+     *
+     * @param mixed the table to be searched (string name or XMLDBTable instance)
+     * @param XMLDBIndex the index to be searched
+     * @return string index name of false
+     */
+    public function find_index_name($table, $xmldb_index) {
+    /// Check the table exists
+        if (!$this->table_exists($table)) {
+            return false;
+        }
+
+    /// Do this function silenty (to avoid output in install/upgrade process)
+        $olddbdebug = $this->mdb->get_debug();
+        $this->mdb->set_debug(false);
+
+    /// Extract index columns
+        $indcolumns = $xmldb_index->getFields();
+
+        if (is_string($table)) {
+            $tablename = $table;
+        } else {
+        /// Calculate the name of the table
+            $tablename = $table->getName();
+        }
+
+    /// Get list of indexes in table
+        $indexes = $this->mdb->get_indexes($tablename);
+
+    /// Iterate over them looking for columns coincidence
+        foreach ($indexes as $indexname => $index) {
+            $columns = $index['columns'];
+        /// Check if index matchs queried index
+            $diferences = array_merge(array_diff($columns, $indcolumns), array_diff($indcolumns, $columns));
+        /// If no diferences, we have find the index
+            if (empty($diferences)) {
+                $this->mdb->set_debug($olddbdebug);
+                return $indexname;
+            }
+        }
+
+    /// Arriving here, index not found
+        $this->mdb->set_debug($olddbdebug);
+        return false;
+    }
+
+    /**
+     * Given one XMLDBIndex, check if it exists in DB (true/false)
+     *
+     * @param mixed the table to be searched (string name or XMLDBTable instance)
+     * @param XMLDBIndex the index to be searched for
+     * @return boolean true/false
+     */
+    public function index_exists($table, $xmldb_index) {
+        return ($this->find_index_name($table, $xmldb_index) !== false);
+    }
+
+    /**
+     * Given one XMLDBField, the function returns the name of the check constraint in DB (if exists)
+     * of false if it doesn't exist. Note that XMLDB limits the number of check constrainst per field
+     * to 1 "enum-like" constraint. So, if more than one is returned, only the first one will be
+     * retrieved by this funcion.
+     *
+     * @uses, $db
+     * @param XMLDBTable the table to be searched
+     * @param XMLDBField the field to be searched
+     * @return string check consrtaint name or false
+     */
+    public function find_check_constraint_name($xmldb_table, $xmldb_field) {
+
+    /// Check the table exists
+        if (!$this->table_exists($xmldb_table)) {
+            return false;
+        }
+
+    /// Check the field exists
+        if (!$this->field_exists($xmldb_table, $xmldb_field)) {
+            return false;
+        }
+
+    /// Do this function silenty (to avoid output in install/upgrade process)
+        $olddbdebug = $this->mdb->get_debug();
+        $this->mdb->set_debug(false);
+
+    /// Get list of check_constraints in table/field
+        $checks = false;
+        if ($objchecks = $this->generator->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
+        /// Get only the 1st element. Shouldn't be more than 1 under XMLDB
+            $objcheck = array_shift($objchecks);
+            if ($objcheck) {
+                $checks = strtolower($objcheck->name);
+            }
+        }
+
+    /// Arriving here, check not found
+        $this->mdb->set_debug($olddbdebug);
+        return $checks;
+    }
+
+    /**
+     * Given one XMLDBField, check if it has a check constraint in DB
+     *
+     * @uses, $db
+     * @param XMLDBTable the table
+     * @param XMLDBField the field to be searched for any existing constraint
+     * @return boolean true/false
+     */
+    public function check_constraint_exists($xmldb_table, $xmldb_field) {
+        return ($this->find_check_constraint_name($xmldb_table, $xmldb_field) !== false);
+    }
+
+    /**
+     * This function IS NOT IMPLEMENTED. ONCE WE'LL BE USING RELATIONAL
+     * INTEGRITY IT WILL BECOME MORE USEFUL. FOR NOW, JUST CALCULATE "OFFICIAL"
+     * KEY NAMES WITHOUT ACCESSING TO DB AT ALL.
+     * Given one XMLDBKey, the function returns the name of the key in DB (if exists)
+     * of false if it doesn't exist
+     *
+     * @uses, $db
+     * @param XMLDBTable the table to be searched
+     * @param XMLDBKey the key to be searched
+     * @return string key name of false
+     */
+    public function find_key_name($xmldb_table, $xmldb_key) {
+
+    /// Extract key columns
+        $keycolumns = $xmldb_key->getFields();
+
+    /// Get list of keys in table
+    /// first primaries (we aren't going to use this now, because the MetaPrimaryKeys is awful)
+        ///TODO: To implement when we advance in relational integrity
+    /// then uniques (note that Moodle, for now, shouldn't have any UNIQUE KEY for now, but unique indexes)
+        ///TODO: To implement when we advance in relational integrity (note that AdoDB hasn't any MetaXXX for this.
+    /// then foreign (note that Moodle, for now, shouldn't have any FOREIGN KEY for now, but indexes)
+        ///TODO: To implement when we advance in relational integrity (note that AdoDB has one MetaForeignKeys()
+        ///but it's far from perfect.
+    /// TODO: To create the proper functions inside each generator to retrieve all the needed KEY info (name
+    ///       columns, reftable and refcolumns
+
+    /// So all we do is to return the official name of the requested key without any confirmation!)
+    /// One exception, harcoded primary constraint names
+        if ($this->generator->primary_key_name && $xmldb_key->getType() == XMLDB_KEY_PRIMARY) {
+            return $this->generator->primary_key_name;
+        } else {
+        /// Calculate the name suffix
+            switch ($xmldb_key->getType()) {
+                case XMLDB_KEY_PRIMARY:
+                    $suffix = 'pk';
+                    break;
+                case XMLDB_KEY_UNIQUE:
+                    $suffix = 'uk';
+                    break;
+                case XMLDB_KEY_FOREIGN_UNIQUE:
+                case XMLDB_KEY_FOREIGN:
+                    $suffix = 'fk';
+                    break;
+            }
+        /// And simply, return the oficial name
+            return $this->generator->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), $suffix);
+        }
+    }
+
+
+    /**
+     * Given one XMLDBTable, the function returns the name of its sequence in DB (if exists)
+     * of false if it doesn't exist
+     *
+     * @param XMLDBTable the table to be searched
+     * @return string sequence name of false
+     */
+    public function find_sequence_name($xmldb_table) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect find_sequence_name() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!$this->table_exists($xmldb_table)) {
+            debugging('Table ' . $xmldb_table->getName() .
+                      ' does not exist. Sequence not found', DEBUG_DEVELOPER);
+            return false; //Table doesn't exist, nothing to do
+
+        }
+
+        $sequencename = false;
+
+    /// Do this function silenty (to avoid output in install/upgrade process)
+        $olddbdebug = $this->mdb->get_debug();
+        $this->mdb->set_debug(false);
+
+        $sequencename = $this->generator->getSequenceFromDB($xmldb_table);
+
+        $this->mdb->set_debug($olddbdebug);
+        return $sequencename;
+    }
+
+    /**
+     * This function will all tables found in XMLDB file from db
+     *
+     * @param $file full path to the XML file to be used
+     * @param $feedback
+     * @return boolean (true on success, false on error)
+     */
+    public function delete_tables_from_xmldb_file($file, $feedback=true ) {
+
+        $xmldb_file = new XMLDBFile($file);
+
+        if (!$xmldb_file->fileExists()) {
+            return false;
+        }
+
+        $loaded    = $xmldb_file->loadXMLStructure();
+        $structure = $xmldb_file->getStructure();
+
+        if (!$loaded || !$xmldb_file->isLoaded()) {
+        /// Show info about the error if we can find it
+            if ($feedback and $structure) {
+                if ($errors = $structure->getAllErrors()) {
+                    notify('Errors found in XMLDB file: '. implode (', ', $errors));
+                }
+            }
+            return false;
+        }
+
+        if ($xmldb_tables = $structure->getTables()) {
+            foreach($xmldb_tables as $table) {
+                if ($this->table_exists($table)) {
+                    $this->drop_table($table, true, $feedback);
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * This function will drop the table passed as argument
+     * and all the associated objects (keys, indexes, constaints, sequences, triggers)
+     * will be dropped too.
+     *
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function drop_table($xmldb_table, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect drop_table() $xmldb_table parameter');
+            return false;
+        }
+
+    /// Check table exists
+        if (!$this->table_exists($xmldb_table)) {
+            debugging('Table ' . $xmldb_table->getName() .
+                      ' does not exist. Delete skipped', DEBUG_DEVELOPER);
+            return true; //Table don't exist, nothing to do
+        }
+
+        if (!$sqlarr = $this->generator->getDropTableSQL($xmldb_table)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will load one entire XMLDB file, generating all the needed
+     * SQL statements, specific for each RDBMS ($CFG->dbtype) and, finally, it
+     * will execute all those statements against the DB.
+     *
+     * @param $file full path to the XML file to be used
+     * @return boolean (true on success, false on error)
+     */
+    public function install_from_xmldb_file($file, $continue=true, $feedback=true) {
+        $xmldb_file = new XMLDBFile($file);
+
+        if (!$xmldb_file->fileExists()) {
+            return false;
+        }
+
+        $loaded = $xmldb_file->loadXMLStructure();
+        if (!$loaded || !$xmldb_file->isLoaded()) {
+        /// Show info about the error if we can find it
+            if ($structure =& $xmldb_file->getStructure()) {
+                if ($errors = $structure->getAllErrors()) {
+                    notify('Errors found in XMLDB file: '. implode (', ', $errors));
+                }
+            }
+            return false;
+        }
+
+        $xmldb_structure = $xmldb_file->getStructure();
+
+        /// Do this function silenty (to avoid output in install/upgrade process)
+        $olddbdebug = $this->mdb->get_debug();
+        $this->mdb->set_debug(false);
+
+        if (!$sqlarr = $this->generator->getCreateStructureSQL($xmldb_structure)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        $this->mdb->set_debug($olddbdebug);
+
+        $result = $this->execute_sql_arr($sqlarr, $continue, $feedback);
+
+        return $result;
+    }
+
+    /**
+     * This function will create the table passed as argument with all its
+     * fields/keys/indexes/sequences, everything based in the XMLDB object
+     *
+     * @param XMLDBTable table object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function create_table($xmldb_table, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect create_table() $xmldb_table parameter');
+            return false;
+        }
+
+    /// Check table doesn't exist
+        if ($this->table_exists($xmldb_table)) {
+            debugging('Table ' . $xmldb_table->getName() .
+                      ' already exists. Create skipped', DEBUG_DEVELOPER);
+            return true; //Table exists, nothing to do
+        }
+
+        if (!$sqlarr = $this->generator->getCreateTableSQL($xmldb_table)) {
+            return true; //Empty array = nothing to do = no error
+        }
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will create the temporary table passed as argument with all its
+     * fields/keys/indexes/sequences, everything based in the XMLDB object
+     *
+     * TRUNCATE the table immediately after creation. A previous process using
+     * the same persistent connection may have created the temp table and failed to
+     * drop it. In that case, the table will exist, and create_temp_table() will
+     * will succeed.
+     *
+     * NOTE: The return value is the tablename - some DBs (MSSQL at least) use special
+     * names for temp tables.
+     *
+     * @param XMLDBTable table object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return string tablename on success, false on error
+     */
+    function create_temp_table($xmldb_table, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect create_table() $xmldb_table parameter');
+            return false;
+        }
+
+    /// Check table doesn't exist
+        if ($this->table_exists($xmldb_table)) {
+            debugging('Table ' . $xmldb_table->getName() .
+                      ' already exists. Create skipped', DEBUG_DEVELOPER);
+            return $xmldb_table->getName(); //Table exists, nothing to do
+        }
+
+        if (!$sqlarr = $this->generator->getCreateTableSQL($xmldb_table)) {
+            return $xmldb_table->getName(); //Empty array = nothing to do = no error
+        }
+
+        if ($this->execute_sql_arr($sqlarr, $continue, $feedback)) {
+            return $xmldb_table->getName();
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * This function will rename the table passed as argument
+     * Before renaming the index, the function will check it exists
+     *
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param string new name of the index
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function rename_table($xmldb_table, $newname, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect rename_table() $xmldb_table parameter');
+            return false;
+        }
+
+    /// Check newname isn't empty
+        if (!$newname) {
+            debugging('Error: new name for table ' . $xmldb_table->getName() .
+                      ' is empty!');
+            return false; //error!
+        }
+
+        $check = new XMLDBTable($newname);
+
+    /// Check table already renamed
+        if (!$this->table_exists($xmldb_table) and $this->table_exists($check)) {
+            debugging('Table ' . $xmldb_table->getName() .
+                      ' already renamed. Rename skipped', DEBUG_DEVELOPER);
+            return true; //ok fine
+        }
+
+    /// Check table exists
+        if (!$this->table_exists($xmldb_table)) {
+            debugging('Table ' . $xmldb_table->getName() .
+                      ' does not exist. Rename skipped');
+            return false; //error!
+        }
+
+    /// Check new table doesn't exist
+        if ($this->table_exists($check)) {
+            debugging('Table ' . $check->getName() .
+                      ' already exists. Rename skipped');
+            return false; //error!
+        }
+
+        if (!$sqlarr = $this->generator->getRenameTableSQL($xmldb_table, $newname)) {
+            return true; //Empty array = nothing to do = no error (this is weird!)
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+
+    /**
+     * This function will add the field to the table passed as arguments
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBField field object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function add_field($xmldb_table, $xmldb_field, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect add_field() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_field instanceof XMLDBField)) {
+            debugging('Incorrect add_field() $xmldb_field parameter');
+            return false;
+        }
+     /// Check the field doesn't exist
+        if ($this->field_exists($xmldb_table, $xmldb_field)) {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' already exists. Create skipped', DEBUG_DEVELOPER);
+            return true;
+        }
+
+    /// If NOT NULL and no default given (we ask the generator about the
+    /// *real* default that will be used) check the table is empty
+        if ($xmldb_field->getNotNull() && $this->generator->getDefaultValue($xmldb_field) === NULL && $this->mdb->count_records($xmldb_table->getName())) {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' cannot be added. Not null fields added to non empty tables require default value. Create skipped', DEBUG_DEVELOPER);
+             return false; //error!!
+        }
+
+        if (!$sqlarr = $this->generator->getAddFieldSQL($xmldb_table, $xmldb_field)) {
+            debugging('Error: No sql code for field adding found');
+            return false;
+        }
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will drop the field from the table passed as arguments
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBField field object (just the name is mandatory)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function drop_field($xmldb_table, $xmldb_field, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect drop_field() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_field instanceof XMLDBField)) {
+            debugging('Incorrect drop_field() $xmldb_field parameter');
+            return false;
+        }
+
+    /// Check the field exists
+        if (!$this->field_exists($xmldb_table, $xmldb_field)) {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' does not exist. Delete skipped', DEBUG_DEVELOPER);
+            return true;
+        }
+
+        if (!$sqlarr = $this->generator->getDropFieldSQL($xmldb_table, $xmldb_field)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will change the type of the field in the table passed as arguments
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBField field object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function change_field_type($xmldb_table, $xmldb_field, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect change_field_type() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_field instanceof XMLDBField)) {
+            debugging('Incorrect change_field_type() $xmldb_field parameter');
+            return false;
+        }
+
+    /// Check the field exists
+        if (!$this->field_exists($xmldb_table, $xmldb_field)) {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' does not exist. Change type skipped');
+            return false;
+        }
+
+        if (!$sqlarr = $this->generator->getAlterFieldSQL($xmldb_table, $xmldb_field)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will change the precision of the field in the table passed as arguments
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBField field object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function change_field_precision($xmldb_table, $xmldb_field, $continue=true, $feedback=true) {
+
+    /// Just a wrapper over change_field_type. Does exactly the same processing
+        return $this->change_field_type($xmldb_table, $xmldb_field, $continue, $feedback);
+    }
+
+    /**
+     * This function will change the unsigned/signed of the field in the table passed as arguments
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBField field object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function change_field_unsigned($xmldb_table, $xmldb_field, $continue=true, $feedback=true) {
+
+    /// Just a wrapper over change_field_type. Does exactly the same processing
+        return $this->change_field_type($xmldb_table, $xmldb_field, $continue, $feedback);
+    }
+
+    /**
+     * This function will change the nullability of the field in the table passed as arguments
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBField field object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function change_field_notnull($xmldb_table, $xmldb_field, $continue=true, $feedback=true) {
+
+    /// Just a wrapper over change_field_type. Does exactly the same processing
+        return $this->change_field_type($xmldb_table, $xmldb_field, $continue, $feedback);
+    }
+
+    /**
+     * This function will change the enum status of the field in the table passed as arguments
+     *
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBField field object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function change_field_enum($xmldb_table, $xmldb_field, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect change_field_enum() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_field instanceof XMLDBField)) {
+            debugging('Incorrect change_field_enum() $xmldb_field parameter');
+            return false;
+        }
+
+    /// Check the field exists
+        if (!$this->field_exists($xmldb_table, $xmldb_field)) {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' does not exist. Change type skipped');
+            return false;
+        }
+
+    /// If enum is defined, we're going to create it, check it doesn't exist.
+        if ($xmldb_field->getEnum()) {
+            if ($this->check_constraint_exists($xmldb_table, $xmldb_field)) {
+                debugging('Enum for ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                          ' already exists. Create skipped', DEBUG_DEVELOPER);
+                return true; //Enum exists, nothing to do
+            }
+        } else { /// Else, we're going to drop it, check it exists
+            if (!$this->check_constraint_exists($xmldb_table, $xmldb_field)) {
+                debugging('Enum for ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                          ' does not exist. Delete skipped', DEBUG_DEVELOPER);
+                return true; //Enum does not exist, nothing to delete
+            }
+        }
+
+        if (!$sqlarr = $this->generator->getModifyEnumSQL($xmldb_table, $xmldb_field)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will change the default of the field in the table passed as arguments
+     * One null value in the default field means delete the default
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBField field object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function change_field_default($xmldb_table, $xmldb_field, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect change_field_default() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_field instanceof XMLDBField)) {
+            debugging('Incorrect change_field_default() $xmldb_field parameter');
+            return false;
+        }
+
+    /// Check the field exists
+        if (!$this->field_exists($xmldb_table, $xmldb_field)) {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' does not exist. Change type skipped');
+            return false;
+        }
+
+        if (!$sqlarr = $this->generator->getModifyDefaultSQL($xmldb_table, $xmldb_field)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will rename the field in the table passed as arguments
+     * Before renaming the field, the function will check it exists
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBField index object (full specs are required)
+     * @param string new name of the field
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function rename_field($xmldb_table, $xmldb_field, $newname, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect rename_field() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_field instanceof XMLDBField)) {
+            debugging('Incorrect rename_field() $xmldb_field parameter');
+            return false;
+        }
+
+        if (empty($newname)) {
+            debugging('New name for field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' is empty! Rename skipped', DEBUG_DEVELOPER);
+            return false; //error
+        }
+
+    /// Check the field exists
+        if (!$this->field_exists($xmldb_table, $xmldb_field)) {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' does not exist. Change type skipped');
+            return false;
+        }
+
+    /// Check we have included full field specs
+        if (!$xmldb_field->getType()) {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' must contain full specs. Rename skipped', DEBUG_DEVELOPER);
+            return false;
+        }
+
+    /// Check field isn't id. Renaming over that field is not allowed
+        if ($xmldb_field->getName() == 'id') {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' cannot be renamed. Rename skipped', DEBUG_DEVELOPER);
+            return false; //Field is "id", nothing to do
+        }
+
+    /// Check field exists
+        if (!$this->field_exists($xmldb_table, $xmldb_field)) {
+            debugging('Field ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
+                      ' does not exist. Rename skipped', DEBUG_DEVELOPER);
+            $newfield = clone($xmldb_field);
+            $newfield->setName($newname);
+            if ($this->field_exists($xmldb_table, $newfield)) {
+                return true; //ok
+            } else {
+                return false; //error
+            }
+        }
+
+        if (!$sqlarr = $this->generator->getRenameFieldSQL($xmldb_table, $xmldb_field, $newname)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will create the key in the table passed as arguments
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBKey index object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function add_key($xmldb_table, $xmldb_key, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect add_key() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_key instanceof XMLDBKey)) {
+            debugging('Incorrect add_key() $xmldb_key parameter');
+            return false;
+        }
+
+        if ($xmldb_key->getType() == XMLDB_KEY_PRIMARY) { // Prevent PRIMARY to be added (only in create table, being serious  :-P)
+            debugging('Primary Keys can be added at table create time only', DEBUG_DEVELOPER);
+            return true;
+        }
+
+        if (!$sqlarr = $this->generator->getAddKeySQL($xmldb_table, $xmldb_key)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will drop the key in the table passed as arguments
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBKey key object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function drop_key($xmldb_table, $xmldb_key, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect drop_key() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_key instanceof XMLDBKey)) {
+            debugging('Incorrect drop_key() $xmldb_key parameter');
+            return false;
+        }
+
+        if ($xmldb_key->getType() == XMLDB_KEY_PRIMARY) { // Prevent PRIMARY to be dropped (only in drop table, being serious  :-P)
+            debugging('Primary Keys can be deleted at table drop time only', DEBUG_DEVELOPER);
+            return true;
+        }
+
+        if(!$sqlarr = $this->generator->getDropKeySQL($xmldb_table, $xmldb_key)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will rename the key in the table passed as arguments
+     * Experimental. Shouldn't be used at all in normal installation/upgrade!
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBKey key object (full specs are required)
+     * @param string new name of the key
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function rename_key($xmldb_table, $xmldb_key, $newname, $continue=true, $feedback=true) {
+        debugging('rename_key() is one experimental feature. You must not use it in production!', DEBUG_DEVELOPER);
+
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect rename_key() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_key instanceof XMLDBKey)) {
+            debugging('Incorrect rename_key() $xmldb_key parameter');
+            return false;
+        }
+
+    /// Check newname isn't empty
+        if (!$newname) {
+            debugging('New name for key ' . $xmldb_table->getName() . '->' . $xmldb_key->getName() .
+                      ' is empty! Rename skipped', DEBUG_DEVELOPER);
+            return true; //Key doesn't exist, nothing to do
+        }
+
+        if (!$sqlarr = $this->generator->getRenameKeySQL($xmldb_table, $xmldb_key, $newname)) {
+            debugging('Some DBs do not support key renaming (MySQL, PostgreSQL, MsSQL). Rename skipped', DEBUG_DEVELOPER);
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will create the index in the table passed as arguments
+     * Before creating the index, the function will check it doesn't exists
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBIndex index object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function add_index($xmldb_table, $xmldb_intex, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect add_index() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_intex instanceof XMLDBIndex)) {
+            debugging('Incorrect add_index() $xmldb_index parameter');
+            return false;
+        }
+
+    /// Check index doesn't exist
+        if ($this->index_exists($xmldb_table, $xmldb_intex)) {
+            debugging('Index ' . $xmldb_table->getName() . '->' . $xmldb_intex->getName() .
+                      ' already exists. Create skipped', DEBUG_DEVELOPER);
+            return true; //Index exists, nothing to do
+        }
+
+        if (!$sqlarr = $this->generator->getAddIndexSQL($xmldb_table, $xmldb_intex)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will drop the index in the table passed as arguments
+     * Before dropping the index, the function will check it exists
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBIndex index object (full specs are required)
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function drop_index($xmldb_table, $xmldb_intex, $continue=true, $feedback=true) {
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect add_index() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_intex instanceof XMLDBIndex)) {
+            debugging('Incorrect add_index() $xmldb_index parameter');
+            return false;
+        }
+
+    /// Check index exists
+        if (!$this->index_exists($xmldb_table, $xmldb_intex)) {
+            debugging('Index ' . $xmldb_table->getName() . '->' . $xmldb_intex->getName() .
+                      ' does not exist. Delete skipped', DEBUG_DEVELOPER);
+            return true; //Index doesn't exist, nothing to do
+        }
+
+        if (!$sqlarr = $this->generator->getDropIndexSQL($xmldb_table, $xmldb_intex)) {
+            return true; //Empty array = nothing to do = no error
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+
+    /**
+     * This function will rename the index in the table passed as arguments
+     * Before renaming the index, the function will check it exists
+     * Experimental. Shouldn't be used at all!
+     *
+     * @uses $CFG, $db
+     * @param XMLDBTable table object (just the name is mandatory)
+     * @param XMLDBIndex index object (full specs are required)
+     * @param string new name of the index
+     * @param boolean continue to specify if must continue on error (true) or stop (false)
+     * @param boolean feedback to specify to show status info (true) or not (false)
+     * @return boolean true on success, false on error
+     */
+    public function rename_index($xmldb_table, $xmldb_intex, $newname, $continue=true, $feedback=true) {
+        debugging('rename_index() is one experimental feature. You must not use it in production!', DEBUG_DEVELOPER);
+
+        if (!($xmldb_table instanceof XMLDBTable)) {
+            debugging('Incorrect add_index() $xmldb_table parameter');
+            return false;
+        }
+
+        if (!($xmldb_intex instanceof XMLDBIndex)) {
+            debugging('Incorrect add_index() $xmldb_index parameter');
+            return false;
+        }
+
+    /// Check newname isn't empty
+        if (!$newname) {
+            debugging('New name for index ' . $xmldb_table->getName() . '->' . $xmldb_intex->getName() .
+                      ' is empty! Rename skipped', DEBUG_DEVELOPER);
+            return true; //Index doesn't exist, nothing to do
+        }
+
+    /// Check index exists
+        if (!$this->index_exists($xmldb_table, $xmldb_intex)) {
+            debugging('Index ' . $xmldb_table->getName() . '->' . $xmldb_intex->getName() .
+                      ' does not exist. Rename skipped', DEBUG_DEVELOPER);
+            return true; //Index doesn't exist, nothing to do
+        }
+
+        if (!$sqlarr = $this->generator->getRenameIndexSQL($xmldb_table, $xmldb_intex, $newname)) {
+            debugging('Some DBs do not support index renaming (MySQL). Rename skipped', DEBUG_DEVELOPER);
+            return false; // Error - index not renamed
+        }
+
+        return $this->execute_sql_arr($sqlarr, $continue, $feedback);
+    }
+}
+
+?>
Index: lib/dml/mssql_adodb_moodle_database.php
===================================================================
RCS file: lib/dml/mssql_adodb_moodle_database.php
diff -N lib/dml/mssql_adodb_moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/mssql_adodb_moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,385 @@
+<?php  //$Id:$
+
+require_once($CFG->libdir.'/dml/moodle_database.php');
+require_once($CFG->libdir.'/dml/adodb_moodle_database.php');
+
+/**
+ * MSSQL database class using adodb backend
+ * @package dmlib
+ */
+class mssql_adodb_moodle_database extends adodb_moodle_database {
+    function __construct ($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        if ($prefix=='') {
+            print_error('prefixcannotbeempty', 'debug', '', array($prefix, $this->get_dbfamily()));
+        }
+
+        parent::__construct($dbhost, $dbuser, $dbpass, $dbname, false, $prefix);
+    }
+
+    protected function configure_dbconnection() {
+        if (!defined('ADODB_ASSOC_CASE')) {
+            define ('ADODB_ASSOC_CASE', 2);
+        }
+        $this->db->SetFetchMode(ADODB_ASSOC_CASE);
+
+        /// No need to set charset. It must be specified in the driver conf
+        /// Allow quoted identifiers
+            $this->db->Execute('SET QUOTED_IDENTIFIER ON');
+        /// Force ANSI nulls so the NULL check was done by IS NULL and NOT IS NULL
+        /// instead of equal(=) and distinct(<>) simbols
+            $this->db->Execute('SET ANSI_NULLS ON');
+        /// Enable sybase quotes, so addslashes and stripslashes will use "'"
+            ini_set('magic_quotes_sybase', '1');
+        /// NOTE: Not 100% useful because GPC has been addslashed with the setting off
+        ///       so IT'S MANDATORY TO CHANGE THIS UNDER php.ini or .htaccess for this DB
+        ///       or to turn off magic_quotes to allow Moodle to do it properly
+
+        return true;
+    }
+
+    /**
+     * Returns database family type
+     * @return string db family name (mysql, postgres, mssql, oracle, etc.)
+     */
+    public function get_dbfamily() {
+        return 'mssql';
+    }
+
+    /**
+     * Returns database type
+     * @return string db type mysql, mysqli, postgres7
+     */
+    protected function get_dbtype() {
+        return 'mssql';
+    }
+
+    /**
+     * Returns supported query parameter types
+     * @return bitmask
+     */
+    protected function allowed_param_types() {
+        return SQL_PARAMS_QM;
+    }
+
+    public function sql_cast_char2int($fieldname, $text=false) {
+        if (!$text) {
+            return ' CAST(' . $fieldname . ' AS INT) ';
+        } else {
+            return ' CAST(' . sql_compare_text($fieldname) . ' AS INT) ';
+        }
+    }
+
+    public function sql_order_by_text($fieldname, $numchars=32) {
+        return 'CONVERT(varchar, ' . $fieldname . ', ' . $numchars . ')';
+    }
+
+    public function sql_isempty($tablename, $fieldname, $nullablefield, $textfield) {
+        if ($textfield) {
+            return " ".sql_compare_text($fieldname)." = '' ";
+        } else {
+            return " $fieldname = '' ";
+        }
+    }
+
+    /**
+     * Update a record in a table
+     *
+     * $dataobject is an object containing needed data
+     * Relies on $dataobject having a variable "id" to
+     * specify the record to update
+     *
+     * @param string $table The database table to be checked against.
+     * @param object $dataobject An object with contents equal to fieldname=>fieldvalue. Must have an entry for 'id' to map to the table specified.
+     * @param bool true means repeated updates expected
+     * @return bool success
+     */
+    public function update_record($table, $dataobject, $bulk=false) {
+
+error('todo');
+
+        global $db, $CFG;
+
+        if (! isset($dataobject->id) ) {
+            return false;
+        }
+
+    /// Check we are handling a proper $dataobject
+        if (is_array($dataobject)) {
+            debugging('Warning. Wrong call to update_record(). $dataobject must be an object. array found instead', DEBUG_DEVELOPER);
+            $dataobject = (object)$dataobject;
+        }
+
+    /// Temporary hack as part of phasing out all access to obsolete user tables  XXX
+        if (!empty($CFG->rolesactive)) {
+            if (in_array($table, array('user_students', 'user_teachers', 'user_coursecreators', 'user_admins'))) {
+                if (debugging()) { var_dump(debug_backtrace()); }
+                print_error('This SQL relies on obsolete tables ('.$table.')!  Your code must be fixed by a developer.');
+            }
+        }
+
+    /// Begin DIRTY HACK
+        if ($CFG->dbfamily == 'oracle') {
+            oracle_dirty_hack($table, $dataobject); // Convert object to the correct "empty" values for Oracle DB
+        }
+    /// End DIRTY HACK
+
+    /// Under Oracle, MSSQL and PostgreSQL we have our own update record process
+    /// detect all the clob/blob fields and delete them from the record being updated
+    /// saving them into $foundclobs and $foundblobs [$fieldname]->contents
+    /// They will be updated later
+        if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres')
+          && !empty($dataobject->id)) {
+        /// Detect lobs
+            $foundclobs = array();
+            $foundblobs = array();
+            db_detect_lobs($table, $dataobject, $foundclobs, $foundblobs, true);
+        }
+
+        // Determine all the fields in the table
+        if (!$columns = $db->MetaColumns($CFG->prefix . $table)) {
+            return false;
+        }
+        $data = (array)$dataobject;
+
+        if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+        // Pull out data matching these fields
+        $update = array();
+        foreach ($columns as $column) {
+            if ($column->name == 'id') {
+                continue;
+            }
+            if (array_key_exists($column->name, $data)) {
+                $key   = $column->name;
+                $value = $data[$key];
+                if (is_null($value)) {
+                    $update[] = "$key = NULL"; // previously NULLs were not updated
+                } else if (is_bool($value)) {
+                    $value = (int)$value;
+                    $update[] = "$key = $value";   // lets keep pg happy, '' is not correct smallint MDL-13038
+                } else {
+                    $update[] = "$key = '$value'"; // All incoming data is already quoted
+                }
+            }
+        }
+
+    /// Only if we have fields to be updated (this will prevent both wrong updates +
+    /// updates of only LOBs in Oracle
+        if ($update) {
+            $query = "UPDATE {$CFG->prefix}{$table} SET ".implode(',', $update)." WHERE id = {$dataobject->id}";
+            if (!$rs = $db->Execute($query)) {
+                debugging($db->ErrorMsg() .'<br /><br />'.s($query));
+                if (!empty($CFG->dblogerror)) {
+                    $debug=array_shift(debug_backtrace());
+                    error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $query");
+                }
+                return false;
+            }
+        }
+
+    /// Under Oracle, MSSQL and PostgreSQL, finally, update all the Clobs and Blobs present in the record
+    /// if we know we have some of them in the query
+        if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') &&
+            !empty($dataobject->id) &&
+            (!empty($foundclobs) || !empty($foundblobs))) {
+            if (!db_update_lobs($table, $dataobject->id, $foundclobs, $foundblobs)) {
+                return false; //Some error happened while updating LOBs
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Insert a record into a table and return the "id" field if required,
+     * Some conversions and safety checks are carried out. Lobs are supported.
+     * If the return ID isn't required, then this just reports success as true/false.
+     * $data is an object containing needed data
+     * @param string $table The database table to be inserted into
+     * @param object $data A data object with values for one or more fields in the record
+     * @param bool $returnid Should the id of the newly created record entry be returned? If this option is not requested then true/false is returned.
+     * @param bool $bulk true means repeated inserts expected
+     * @return mixed success or new ID
+     */
+    public function insert_record($table, $dataobject, $returnid=true, $bulk=false) {
+error('todo');
+
+    ///////////////////////////////////////////////////////////////
+    /// TODO: keeping this for now - only mysql implemented ;-) ///
+    ///////////////////////////////////////////////////////////////
+
+        global $db, $CFG, $empty_rs_cache;
+
+        if (empty($db)) {
+            return false;
+        }
+
+    /// Check we are handling a proper $dataobject
+        if (is_array($dataobject)) {
+            debugging('Warning. Wrong call to insert_record(). $dataobject must be an object. array found instead', DEBUG_DEVELOPER);
+            $dataobject = (object)$dataobject;
+        }
+
+    /// Temporary hack as part of phasing out all access to obsolete user tables  XXX
+        if (!empty($CFG->rolesactive)) {
+            if (in_array($table, array('user_students', 'user_teachers', 'user_coursecreators', 'user_admins'))) {
+                if (debugging()) { var_dump(debug_backtrace()); }
+                print_error('This SQL relies on obsolete tables ('.$table.')!  Your code must be fixed by a developer.');
+            }
+        }
+
+        if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+    /// In Moodle we always use auto-numbering fields for the primary key
+    /// so let's unset it now before it causes any trouble later
+        unset($dataobject->{$primarykey});
+
+    /// Get an empty recordset. Cache for multiple inserts.
+        if (empty($empty_rs_cache[$table])) {
+            /// Execute a dummy query to get an empty recordset
+            if (!$empty_rs_cache[$table] = $db->Execute('SELECT * FROM '. $CFG->prefix . $table .' WHERE '. $primarykey  .' = \'-1\'')) {
+                return false;
+            }
+        }
+
+        $rs = $empty_rs_cache[$table];
+
+    /// Postgres doesn't have the concept of primary key built in
+    /// and will return the OID which isn't what we want.
+    /// The efficient and transaction-safe strategy is to
+    /// move the sequence forward first, and make the insert
+    /// with an explicit id.
+        if ( $CFG->dbfamily === 'postgres' && $returnid == true ) {
+            if ($nextval = (int)get_field_sql("SELECT NEXTVAL('{$CFG->prefix}{$table}_{$primarykey}_seq')")) {
+                $dataobject->{$primarykey} = $nextval;
+            }
+        }
+
+    /// Begin DIRTY HACK
+        if ($CFG->dbfamily == 'oracle') {
+            oracle_dirty_hack($table, $dataobject); // Convert object to the correct "empty" values for Oracle DB
+        }
+    /// End DIRTY HACK
+
+    /// Under Oracle, MSSQL and PostgreSQL we have our own insert record process
+    /// detect all the clob/blob fields and change their contents to @#CLOB#@ and @#BLOB#@
+    /// saving them into $foundclobs and $foundblobs [$fieldname]->contents
+    /// Same for mssql (only processing blobs - image fields)
+        if ($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') {
+            $foundclobs = array();
+            $foundblobs = array();
+            db_detect_lobs($table, $dataobject, $foundclobs, $foundblobs);
+        }
+
+    /// Under Oracle, if the primary key inserted has been requested OR
+    /// if there are LOBs to insert, we calculate the next value via
+    /// explicit query to the sequence.
+    /// Else, the pre-insert trigger will do the job, because the primary
+    /// key isn't needed at all by the rest of PHP code
+        if ($CFG->dbfamily === 'oracle' && ($returnid == true || !empty($foundclobs) || !empty($foundblobs))) {
+        /// We need this here (move this function to dmlib?)
+            include_once($CFG->libdir . '/ddllib.php');
+            $xmldb_table = new XMLDBTable($table);
+            $seqname = find_sequence_name($xmldb_table);
+            if (!$seqname) {
+            /// Fallback, seqname not found, something is wrong. Inform and use the alternative getNameForObject() method
+                debugging('Sequence name for table ' . $table->getName() . ' not found', DEBUG_DEVELOPER);
+                $generator = new XMLDBoci8po();
+                $generator->setPrefix($CFG->prefix);
+                $seqname = $generator->getNameForObject($table, $primarykey, 'seq');
+            }
+            if ($nextval = (int)$db->GenID($seqname)) {
+                $dataobject->{$primarykey} = $nextval;
+            } else {
+                debugging('Not able to get value from sequence ' . $seqname, DEBUG_DEVELOPER);
+            }
+        }
+
+    /// Get the correct SQL from adoDB
+        if (!$insertSQL = $db->GetInsertSQL($rs, (array)$dataobject, true)) {
+            return false;
+        }
+
+    /// Under Oracle, MSSQL and PostgreSQL, replace all the '@#CLOB#@' and '@#BLOB#@' ocurrences to proper default values
+    /// if we know we have some of them in the query
+        if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') &&
+          (!empty($foundclobs) || !empty($foundblobs))) {
+        /// Initial configuration, based on DB
+            switch ($CFG->dbfamily) {
+                case 'oracle':
+                    $clobdefault = 'empty_clob()'; //Value of empty default clobs for this DB
+                    $blobdefault = 'empty_blob()'; //Value of empty default blobs for this DB
+                    break;
+                case 'mssql':
+                case 'postgres':
+                    $clobdefault = 'null'; //Value of empty default clobs for this DB (under mssql this won't be executed
+                    $blobdefault = 'null'; //Value of empty default blobs for this DB
+                    break;
+            }
+            $insertSQL = str_replace("'@#CLOB#@'", $clobdefault, $insertSQL);
+            $insertSQL = str_replace("'@#BLOB#@'", $blobdefault, $insertSQL);
+        }
+
+    /// Run the SQL statement
+        if (!$rs = $db->Execute($insertSQL)) {
+            debugging($db->ErrorMsg() .'<br /><br />'.s($insertSQL));
+            if (!empty($CFG->dblogerror)) {
+                $debug=array_shift(debug_backtrace());
+                error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $insertSQL");
+            }
+            return false;
+        }
+
+    /// Under Oracle and PostgreSQL, finally, update all the Clobs and Blobs present in the record
+    /// if we know we have some of them in the query
+        if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'postgres') &&
+          !empty($dataobject->{$primarykey}) &&
+          (!empty($foundclobs) || !empty($foundblobs))) {
+            if (!db_update_lobs($table, $dataobject->{$primarykey}, $foundclobs, $foundblobs)) {
+                return false; //Some error happened while updating LOBs
+            }
+        }
+
+    /// If a return ID is not needed then just return true now (but not in MSSQL DBs, where we may have some pending tasks)
+        if (!$returnid && $CFG->dbfamily != 'mssql') {
+            return true;
+        }
+
+    /// We already know the record PK if it's been passed explicitly,
+    /// or if we've retrieved it from a sequence (Postgres and Oracle).
+        if (!empty($dataobject->{$primarykey})) {
+            return $dataobject->{$primarykey};
+        }
+
+    /// This only gets triggered with MySQL and MSQL databases
+    /// however we have some postgres fallback in case we failed
+    /// to find the sequence.
+        $id = $db->Insert_ID();
+
+    /// Under MSSQL all the Clobs and Blobs (IMAGE) present in the record
+    /// if we know we have some of them in the query
+        if (($CFG->dbfamily == 'mssql') &&
+          !empty($id) &&
+          (!empty($foundclobs) || !empty($foundblobs))) {
+            if (!db_update_lobs($table, $id, $foundclobs, $foundblobs)) {
+                return false; //Some error happened while updating LOBs
+            }
+        }
+
+        if ($CFG->dbfamily === 'postgres') {
+            // try to get the primary key based on id
+            if ( ($rs = $db->Execute('SELECT '. $primarykey .' FROM '. $CFG->prefix . $table .' WHERE oid = '. $id))
+                 && ($rs->RecordCount() == 1) ) {
+                trigger_error("Retrieved $primarykey from oid on table $table because we could not find the sequence.");
+                return (integer)reset($rs->fields);
+            }
+            trigger_error('Failed to retrieve primary key after insert: SELECT '. $primarykey .
+                          ' FROM '. $CFG->prefix . $table .' WHERE oid = '. $id);
+            return false;
+        }
+
+        return (integer)$id;
+
+    }
+
+}
Index: lib/xmldb/XMLDBStructure.class.php
===================================================================
RCS file: lib/xmldb/XMLDBStructure.class.php
diff -N lib/xmldb/XMLDBStructure.class.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/xmldb/XMLDBStructure.class.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,719 @@
+<?php // $Id: XMLDBStructure.class.php,v 1.12 2007/10/10 05:25:14 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represent one XMLDB structure
+
+class XMLDBStructure extends XMLDBObject {
+
+    var $path;
+    var $version;
+    var $tables;
+    var $statements;
+
+    /**
+     * Creates one new XMLDBStructure
+     */
+    function XMLDBStructure($name) {
+        parent::XMLDBObject($name);
+        $this->path = NULL;
+        $this->version = NULL;
+        $this->tables = array();
+        $this->statements = array();
+    }
+
+    /**
+     * Returns the path of the structure
+     */
+    function getPath() {
+        return $this->path;
+    }
+
+    /**
+     * Returns the version of the structure
+     */
+    function getVersion() {
+        return $this->version;
+    }
+
+    /**
+     * Returns one XMLDBTable
+     */
+    function &getTable($tablename) {
+        $i = $this->findTableInArray($tablename);
+        if ($i !== NULL) {
+            return $this->tables[$i];
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * Returns the position of one table in the array.
+     */
+    function &findTableInArray($tablename) {
+        foreach ($this->tables as $i => $table) {
+            if ($tablename == $table->getName()) {
+                return $i;
+            }
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * Returns the position of one statement in the array.
+     */
+    function &findStatementInArray($statementname) {
+        foreach ($this->statements as $i => $statement) {
+            if ($statementname == $statement->getName()) {
+                return $i;
+            }
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * This function will reorder the array of tables
+     */
+    function orderTables() {
+        $result = $this->orderElements($this->tables);
+        if ($result) {
+            $this->setTables($result);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * This function will reorder the array of statements
+     */
+    function orderStatements() {
+        $result = $this->orderElements($this->statements);
+        if ($result) {
+            $this->setStatements($result);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the tables of the structure
+     */
+    function &getTables() {
+        return $this->tables;
+    }
+
+    /**
+     * Returns one XMLDBStatement
+     */
+    function &getStatement($statementname) {
+        $i = $this->findStatementInArray($statementname);
+        if ($i !== NULL) {
+            return $this->statements[$i];
+        }
+        $null = NULL;
+        return $null;
+    }
+
+    /**
+     * Returns the statements of the structure
+     */
+    function &getStatements() {
+        return $this->statements;
+    }
+
+    /**
+     * Set the structure version
+     */
+    function setVersion($version) {
+        $this->version = $version;
+    }
+
+    /**
+     * Add one table to the structure, allowing to specify the desired order
+     * If it's not specified, then the table is added at the end.
+     */
+    function addTable(&$table, $after=NULL) {
+
+    /// Calculate the previous and next tables
+        $prevtable = NULL;
+        $nexttable = NULL;
+
+        if (!$after) {
+            $alltables =& $this->getTables();
+            if ($alltables) {
+                end($alltables);
+                $prevtable =& $alltables[key($alltables)];
+            }
+        } else {
+            $prevtable =& $this->getTable($after);
+        }
+        if ($prevtable && $prevtable->getNext()) {
+            $nexttable =& $this->getTable($prevtable->getNext());
+        }
+
+    /// Set current table previous and next attributes
+        if ($prevtable) {
+            $table->setPrevious($prevtable->getName());
+            $prevtable->setNext($table->getName());
+        }
+        if ($nexttable) {
+            $table->setNext($nexttable->getName());
+            $nexttable->setPrevious($table->getName());
+        }
+    /// Some more attributes
+        $table->setLoaded(true);
+        $table->setChanged(true);
+    /// Add the new table
+        $this->tables[] =& $table;
+    /// Reorder the whole structure
+        $this->orderTables($this->tables);
+    /// Recalculate the hash
+        $this->calculateHash(true);
+    /// We have one new table, so the structure has changed
+        $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
+        $this->setChanged(true);
+    }
+
+    /**
+     * Add one statement to the structure, allowing to specify the desired order
+     * If it's not specified, then the statement is added at the end.
+     */
+    function addStatement(&$statement, $after=NULL) {
+
+    /// Calculate the previous and next tables
+        $prevstatement = NULL;
+        $nextstatement = NULL;
+
+        if (!$after) {
+            $allstatements =& $this->getStatements();
+            if ($allstatements) {
+                end($allstatements);
+                $prevstatement =& $allstatements[key($allstatements)];
+            }
+        } else {
+            $prevstatement =& $this->getStatement($after);
+        }
+        if ($prevstatement && $prevstatement->getNext()) {
+            $nextstatement =& $this->getStatement($prevstatement->getNext());
+        }
+
+    /// Set current statement previous and next attributes
+        if ($prevstatement) {
+            $statement->setPrevious($prevstatement->getName());
+            $prevstatement->setNext($statement->getName());
+        }
+        if ($nextstatement) {
+            $statement->setNext($nextstatement->getName());
+            $nextstatement->setPrevious($statement->getName());
+        }
+    /// Some more attributes
+        $statement->setLoaded(true);
+        $statement->setChanged(true);
+    /// Add the new statement
+        $this->statements[] =& $statement;
+    /// Reorder the whole structure
+        $this->orderStatements($this->statements);
+    /// Recalculate the hash
+        $this->calculateHash(true);
+    /// We have one new statement, so the structure has changed
+        $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
+        $this->setChanged(true);
+    }
+
+    /**
+     * Delete one table from the Structure
+     */
+    function deleteTable($tablename) {
+
+        $table =& $this->getTable($tablename);
+        if ($table) {
+            $i = $this->findTableInArray($tablename);
+            $prevtable = NULL;
+            $nexttable = NULL;
+        /// Look for prev and next table
+            $prevtable =& $this->getTable($table->getPrevious());
+            $nexttable =& $this->getTable($table->getNext());
+        /// Change their previous and next attributes
+            if ($prevtable) {
+                $prevtable->setNext($table->getNext());
+            }
+            if ($nexttable) {
+                $nexttable->setPrevious($table->getPrevious());
+            }
+        /// Delete the table
+            unset($this->tables[$i]);
+        /// Reorder the tables
+            $this->orderTables($this->tables);
+        /// Recalculate the hash
+            $this->calculateHash(true);
+        /// We have one deleted table, so the structure has changed
+            $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
+            $this->setChanged(true);
+        }
+    }
+
+    /**
+     * Delete one statement from the Structure
+     */
+    function deleteStatement($statementname) {
+
+        $statement =& $this->getStatement($statementname);
+        if ($statement) {
+            $i = $this->findStatementInArray($statementname);
+            $prevstatement = NULL;
+            $nextstatement = NULL;
+        /// Look for prev and next statement
+            $prevstatement =& $this->getStatement($statement->getPrevious());
+            $nextstatement =& $this->getStatement($statement->getNext());
+        /// Change their previous and next attributes
+            if ($prevstatement) {
+                $prevstatement->setNext($statement->getNext());
+            }
+            if ($nextstatement) {
+                $nextstatement->setPrevious($statement->getPrevious());
+            }
+        /// Delete the statement
+            unset($this->statements[$i]);
+        /// Reorder the statements
+            $this->orderStatements($this->statements);
+        /// Recalculate the hash
+            $this->calculateHash(true);
+        /// We have one deleted statement, so the structure has changed
+            $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
+            $this->setChanged(true);
+        }
+    }
+
+    /**
+     * Set the tables
+     */
+    function setTables(&$tables) {
+        $this->tables = $tables;
+    }
+
+    /**
+     * Set the statements
+     */
+    function setStatements(&$statements) {
+        $this->statements = $statements;
+    }
+
+    /**
+     * Load data from XML to the structure
+     */
+    function arr2XMLDBStructure($xmlarr) {
+
+        global $CFG;
+
+        $result = true;
+
+    /// Debug the structure
+    /// traverse_xmlize($xmlarr);                   //Debug
+    /// print_object ($GLOBALS['traverse_array']);  //Debug
+    /// $GLOBALS['traverse_array']="";              //Debug
+
+    /// Process structure attributes (path, comment and version)
+        if (isset($xmlarr['XMLDB']['@']['PATH'])) {
+            $this->path = trim($xmlarr['XMLDB']['@']['PATH']);
+        } else {
+            $this->errormsg = 'Missing PATH attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+        if (isset($xmlarr['XMLDB']['@']['VERSION'])) {
+            $this->version = trim($xmlarr['XMLDB']['@']['VERSION']);
+        } else {
+            $this->errormsg = 'Missing VERSION attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+        if (isset($xmlarr['XMLDB']['@']['COMMENT'])) {
+            $this->comment = trim($xmlarr['XMLDB']['@']['COMMENT']);
+        } else if (!empty($CFG->xmldbdisablecommentchecking)) {
+            $this->comment = '';
+        } else {
+            $this->errormsg = 'Missing COMMENT attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+    /// Iterate over tables
+        if (isset($xmlarr['XMLDB']['#']['TABLES']['0']['#']['TABLE'])) {
+            foreach ($xmlarr['XMLDB']['#']['TABLES']['0']['#']['TABLE'] as $xmltable) {
+                if (!$result) { //Skip on error
+                    continue;
+                }
+                $name = trim($xmltable['@']['NAME']);
+                $table = new XMLDBTable($name);
+                $table->arr2XMLDBTable($xmltable);
+                $this->tables[] = $table;
+                if (!$table->isLoaded()) {
+                    $this->errormsg = 'Problem loading table ' . $name;
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            }
+        } else {
+            $this->errormsg = 'Missing TABLES section';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+    /// Perform some general checks over tables
+        if ($result && $this->tables) {
+        /// Check tables names are ok (lowercase, a-z _-)
+            if (!$this->checkNameValues($this->tables)) {
+                $this->errormsg = 'Some TABLES name values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Check previous & next are ok (duplicates and existing tables)
+            $this->fixPrevNext($this->tables);
+            if ($result && !$this->checkPreviousNextValues($this->tables)) {
+                $this->errormsg = 'Some TABLES previous/next values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Order tables
+            if ($result && !$this->orderTables($this->tables)) {
+                $this->errormsg = 'Error ordering the tables';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        }
+
+    /// Iterate over statements
+        if (isset($xmlarr['XMLDB']['#']['STATEMENTS']['0']['#']['STATEMENT'])) {
+            foreach ($xmlarr['XMLDB']['#']['STATEMENTS']['0']['#']['STATEMENT'] as $xmlstatement) {
+                if (!$result) { //Skip on error
+                    continue;
+                }
+                $name = trim($xmlstatement['@']['NAME']);
+                $statement = new XMLDBStatement($name);
+                $statement->arr2XMLDBStatement($xmlstatement);
+                $this->statements[] = $statement;
+                if (!$statement->isLoaded()) {
+                    $this->errormsg = 'Problem loading statement ' . $name;
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            }
+        }
+
+    /// Perform some general checks over statements
+        if ($result && $this->statements) {
+        /// Check statements names are ok (lowercase, a-z _-)
+            if (!$this->checkNameValues($this->statements)) {
+                $this->errormsg = 'Some STATEMENTS name values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Check previous & next are ok (duplicates and existing statements)
+            $this->fixPrevNext($this->statements);
+            if ($result && !$this->checkPreviousNextValues($this->statements)) {
+                $this->errormsg = 'Some STATEMENTS previous/next values are incorrect';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        /// Order statements
+            if ($result && !$this->orderStatements($this->statements)) {
+                $this->errormsg = 'Error ordering the statements';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        }
+
+    /// Set some attributes
+        if ($result) {
+            $this->loaded = true;
+        }
+        $this->calculateHash();
+        return $result;
+    }
+
+    /**
+     * This function calculate and set the hash of one XMLDBStructure
+     */
+     function calculateHash($recursive = false) {
+        if (!$this->loaded) {
+            $this->hash = NULL;
+        } else {
+            $key = $this->name . $this->path . $this->comment;
+            if ($this->tables) {
+                foreach ($this->tables as $tbl) {
+                    $table =& $this->getTable($tbl->getName());
+                    if ($recursive) {
+                        $table->calculateHash($recursive);
+                    }
+                    $key .= $table->getHash();
+                }
+            }
+            if ($this->statements) {
+                foreach ($this->statements as $sta) {
+                    $statement =& $this->getStatement($sta->getName());
+                    if ($recursive) {
+                        $statement->calculateHash($recursive);
+                    }
+                    $key .= $statement->getHash();
+                }
+            }
+            $this->hash = md5($key);
+        }
+    }
+
+    /**
+     * This function will output the XML text for one structure
+     */
+    function xmlOutput() {
+        $o = '<?xml version="1.0" encoding="UTF-8" ?>' . "\n";
+        $o.= '<XMLDB PATH="' . $this->path . '"';
+        $o.= ' VERSION="' . $this->version . '"';
+        if ($this->comment) {
+            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"'."\n";
+        }
+        $rel = array_fill(0, count(explode('/', $this->path)), '..');
+        $rel = implode('/', $rel);
+        $o.= '    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'."\n";
+        $o.= '    xsi:noNamespaceSchemaLocation="'.$rel.'/lib/xmldb/xmldb.xsd"'."\n";
+        $o.= '>' . "\n";
+    /// Now the tables
+        if ($this->tables) {
+            $o.= '  <TABLES>' . "\n";
+            foreach ($this->tables as $table) {
+                $o.= $table->xmlOutput();
+            }
+            $o.= '  </TABLES>' . "\n";
+        }
+    /// Now the statements
+        if ($this->statements) {
+            $o.= '  <STATEMENTS>' . "\n";
+            foreach ($this->statements as $statement) {
+                $o.= $statement->xmlOutput();
+            }
+            $o.= '  </STATEMENTS>' . "\n";
+        }
+        $o.= '</XMLDB>';
+
+        return $o;
+    }
+
+    /**
+     * This function returns the number of uses of one table inside
+     * a whole XMLDStructure. Useful to detect if the table must be
+     * locked. Return false if no uses are found.
+     */
+    function getTableUses($tablename) {
+
+        $uses = array();
+
+    /// Check if some foreign key in the whole structure is using it
+    /// (by comparing the reftable with the tablename)
+        $alltables = $this->getTables();
+        if ($alltables) {
+            foreach ($alltables as $table) {
+                $keys = $table->getKeys();
+                if ($keys) {
+                    foreach ($keys as $key) {
+                        if ($key->getType() == XMLDB_KEY_FOREIGN) {
+                            if ($tablename == $key->getRefTable()) {
+                                $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+    /// Return result
+        if (!empty($uses)) {
+            return $uses;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * This function returns the number of uses of one field inside
+     * a whole XMLDBStructure. Useful to detect if the field must be
+     * locked. Return false if no uses are found.
+     */
+    function getFieldUses($tablename, $fieldname) {
+
+        $uses = array();
+
+    /// Check if any key in the table is using it
+        $table = $this->getTable($tablename);
+        if ($keys = $table->getKeys()) {
+            foreach ($keys as $key) {
+                if (in_array($fieldname, $key->getFields()) ||
+                    in_array($fieldname, $key->getRefFields())) {
+                        $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
+                }
+            }
+        }
+    /// Check if any index in the table is using it
+        $table = $this->getTable($tablename);
+        if ($indexes = $table->getIndexes()) {
+            foreach ($indexes as $index) {
+                if (in_array($fieldname, $index->getFields())) {
+                    $uses[] = 'table ' . $table->getName() . ' index ' . $index->getName();
+                }
+            }
+        }
+    /// Check if some foreign key in the whole structure is using it
+    /// By comparing the reftable and refields with the field)
+        $alltables = $this->getTables();
+        if ($alltables) {
+            foreach ($alltables as $table) {
+                $keys = $table->getKeys();
+                if ($keys) {
+                    foreach ($keys as $key) {
+                        if ($key->getType() == XMLDB_KEY_FOREIGN) {
+                            if ($tablename == $key->getRefTable()) {
+                                $reffieds = $key->getRefFields();
+                                if (in_array($fieldname, $key->getRefFields())) {
+                                    $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+    /// Return result
+        if (!empty($uses)) {
+            return $uses;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * This function returns the number of uses of one key inside
+     * a whole XMLDBStructure. Useful to detect if the key must be
+     * locked. Return false if no uses are found.
+     */
+    function getKeyUses($tablename, $keyname) {
+
+        $uses = array();
+
+    /// Check if some foreign key in the whole structure is using it
+    /// (by comparing the reftable and reffields with the fields in the key)
+        $mytable = $this->getTable($tablename);
+        $mykey = $mytable->getKey($keyname);
+        $alltables = $this->getTables();
+        if ($alltables && $mykey) {
+            foreach ($alltables as $table) {
+                $allkeys = $table->getKeys();
+                if ($allkeys) {
+                    foreach ($allkeys as $key) {
+                        if ($key->getType() != XMLDB_KEY_FOREIGN) {
+                            continue;
+                        }
+                        if ($key->getRefTable() == $tablename &&
+                            implode(',', $key->getRefFields()) == implode(',', $mykey->getFields())) {
+                                $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
+                        }
+                    }
+                }
+            }
+        }
+
+    /// Return result
+        if (!empty($uses)) {
+            return $uses;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * This function returns the number of uses of one index inside
+     * a whole XMLDBStructure. Useful to detect if the index must be
+     * locked. Return false if no uses are found.
+     */
+    function getIndexUses($tablename, $indexname) {
+
+        $uses = array();
+
+    /// Nothing to check, beause indexes haven't uses! Leave it here
+    /// for future checks...
+
+    /// Return result
+        if (!empty($uses)) {
+            return $uses;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * This function will return all the errors found in one structure
+     * looking recursively inside each table/statement. Returns
+     * an array of errors or false
+     */
+    function getAllErrors() {
+
+        $errors = array();
+    /// First the structure itself
+        if ($this->getError()) {
+            $errors[] = $this->getError();
+        }
+    /// Delegate to tables
+        if ($tables = $this->getTables()) {
+            foreach ($tables as $table) {
+                if ($tableerrors = $table->getAllErrors()) {
+
+                }
+            }
+        /// Add them to the errors array
+            if ($tableerrors) {
+                $errors = array_merge($errors, $tableerrors);
+            }
+        }
+    /// Delegate to statements
+        if ($statements = $this->getStatements()) {
+            foreach ($statements as $statement) {
+                if ($statement->getError()) {
+                    $errors[] = $statement->getError();
+                }
+            }
+        }
+    /// Return decision
+        if (count($errors)) {
+            return $errors;
+        } else {
+            return false;
+        }
+    }
+}
+
+?>
Index: lib/ddl/sql_generator.php
===================================================================
RCS file: lib/ddl/sql_generator.php
diff -N lib/ddl/sql_generator.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/ddl/sql_generator.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1253 @@
+<?php // $Id: XMLDBGenerator.class.php,v 1.66 2007/10/10 05:25:25 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas     http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represent the base generator class where all the
+/// needed functions to generate proper SQL are defined.
+
+/// The rest of classes will inherit, by default, the same logic.
+/// Functions will be overriden as needed to generate correct SQL.
+
+abstract class sql_generator {
+
+/// Please, avoid editing this defaults in this base class!
+/// It could change the behaviour of the rest of generators
+/// that, by default, inherit this configuration.
+/// To change any of them, do it in extended classes instead.
+
+    public $quote_string = '"';   // String used to quote names
+
+    public $statement_end = ';'; // String to be automatically added at the end of each statement
+
+    public $quote_all    = false; // To decide if we want to quote all the names or only the reserved ones
+
+    public $integer_to_number = false;  // To create all the integers as NUMBER(x) (also called DECIMAL, NUMERIC...)
+    public $float_to_number   = false;  // To create all the floats as NUMBER(x) (also called DECIMAL, NUMERIC...)
+
+    public $number_type = 'NUMERIC';    // Proper type for NUMBER(x) in this DB
+
+    public $unsigned_allowed = true;    // To define in the generator must handle unsigned information
+    public $default_for_char = null;      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
+
+    public $drop_default_value_required = false; //To specify if the generator must use some DEFAULT clause to drop defaults
+    public $drop_default_value = ''; //The DEFAULT clause required to drop defaults
+
+    public $default_after_null = true;  //To decide if the default clause of each field must go after the null clause
+
+    public $specify_nulls = false;  //To force the generator if NULL clauses must be specified. It shouldn't be necessary
+                                 //but some mssql drivers require them or everything is created as NOT NULL :-(
+
+    public $primary_key_name = null; //To force primary key names to one string (null=no force)
+
+    public $primary_keys = true;  // Does the generator build primary keys
+    public $unique_keys = false;  // Does the generator build unique keys
+    public $foreign_keys = false; // Does the generator build foreign keys
+
+    public $drop_primary_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop PKs
+                               // with automatic replace for TABLENAME and KEYNAME
+
+    public $drop_unique_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop UKs
+                               // with automatic replace for TABLENAME and KEYNAME
+
+    public $drop_foreign_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop FKs
+                               // with automatic replace for TABLENAME and KEYNAME
+
+    public $sequence_extra_code = true; //Does the generator need to add extra code to generate the sequence fields
+    public $sequence_name = 'auto_increment'; //Particular name for inline sequences in this generator
+    public $sequence_name_small = false; //Different name for small (4byte) sequences or false if same
+    public $sequence_only = false; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name publiciable
+
+    public $enum_inline_code = true; //Does the generator need to add inline code in the column definition
+    public $enum_extra_code = true; //Does the generator need to add extra code to generate code for the enums in the table
+
+    public $add_table_comments  = true;  // Does the generator need to add code for table comments
+
+    public $add_after_clause = false; // Does the generator need to add the after clause for fields
+
+    public $prefix_on_names = true; //Does the generator need to prepend the prefix to all the key/index/sequence/trigger/check names
+
+    public $names_max_length = 30; //Max length for key/index/sequence/trigger/check names (keep 30 for all!)
+
+    public $concat_character = '||'; //Characters to be used as concatenation operator. If not defined
+                                  //MySQL CONCAT function will be used
+
+    public $rename_table_sql = 'ALTER TABLE OLDNAME RENAME TO NEWNAME'; //SQL sentence to rename one table, both
+                                  //OLDNAME and NEWNAME are dinamically replaced
+
+    public $drop_table_sql = 'DROP TABLE TABLENAME'; //SQL sentence to drop one table
+                                  //TABLENAME is dinamically replaced
+
+    public $alter_column_sql = 'ALTER TABLE TABLENAME ALTER COLUMN COLUMNSPECS'; //The SQL template to alter columns
+
+    public $alter_column_skip_default = false; //The generator will skip the default clause on alter columns
+
+    public $alter_column_skip_type = false; //The generator will skip the type clause on alter columns
+
+    public $alter_column_skip_notnull = false; //The generator will skip the null/notnull clause on alter columns
+
+    public $rename_column_sql = 'ALTER TABLE TABLENAME RENAME COLUMN OLDFIELDNAME TO NEWFIELDNAME';
+                                  ///TABLENAME, OLDFIELDNAME and NEWFIELDNAME are dianmically replaced
+
+    public $drop_index_sql = 'DROP INDEX INDEXNAME'; //SQL sentence to drop one index
+                                  //TABLENAME, INDEXNAME are dinamically replaced
+
+    public $rename_index_sql = 'ALTER INDEX OLDINDEXNAME RENAME TO NEWINDEXNAME'; //SQL sentence to rename one index
+                                  //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dinamically replaced
+
+    public $rename_key_sql = 'ALTER TABLE TABLENAME CONSTRAINT OLDKEYNAME RENAME TO NEWKEYNAME'; //SQL sentence to rename one key
+                                  //TABLENAME, OLDKEYNAME, NEWKEYNAME are dinamically replaced
+
+    public $prefix;         // Prefix to be used for all the DB objects
+
+    public $reserved_words; // List of reserved words (in order to quote them properly)
+
+    public $mdb;
+
+    /**
+     * Creates new sql_generator
+     * @param object moodle_database instance
+     */
+    public function __construct($mdb) {
+        $this->prefix         = $mdb->get_prefix();
+        $this->reserved_words = $this->getReservedWords();
+        $this->mdb            = $mdb; // this creates circular reference - the other link must be unset when closing db
+    }
+
+    /**
+     * Given one string (or one array), ends it with statement_end
+     */
+    public function getEndedStatements($input) {
+
+        if (is_array($input)) {
+            foreach ($input as $key=>$content) {
+                $input[$key] = $this->getEndedStatements($content);
+            }
+            return $input;
+        } else {
+            $input = trim($input).$this->statement_end;
+            return $input;
+        }
+    }
+
+    /**
+     * This function will return the SQL code needed to create db tables and statements
+     */
+    public function getCreateStructureSQL($xmldb_structure) {
+        $results = array();
+
+        if ($tables = $xmldb_structure->getTables()) {
+            foreach ($tables as $table) {
+                $results = array_merge($results, $this->getCreateTableSQL($table));
+            }
+        }
+
+        if ($statements = $xmldb_structure->getStatements()) {
+            foreach ($statements as $statement) {
+                $results = array_merge($results, $this->getExecuteStatementSQL($statement));
+            }
+        }
+        return $results;
+    }
+
+    /**
+     * This function will return the code needed to execute a collection
+     * of sentences present inside one statement for the specified BD
+     * and prefix.
+     * For now it only supports INSERT statements
+     */
+    public function getExecuteStatementSQL($xmldb_statement) {
+
+        $results = array();
+
+    /// Based on statement type
+        switch ($xmldb_statement->type) {
+            case XMLDB_STATEMENT_INSERT:
+                $results = $this->getExecuteInsertSQL($xmldb_statement);
+                break;
+            case XMLDB_STATEMENT_UPDATE:
+                break;
+            case XMLDB_STATEMENT_DELETE:
+                break;
+            case XMLDB_STATEMENT_CUSTOM:
+                break;
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable, returns it's correct name, depending of all the parametrization
+     *
+     * @param XMLDBTable table whose name we want
+     * @param boolean to specify if the name must be quoted (if reserved word, only!)
+     * @return string the correct name of the table
+     */
+    public function getTableName($xmldb_table, $quoted=true) {
+    /// Get the name
+        $tablename = $this->prefix.$xmldb_table->getName();
+
+    /// Apply quotes optionally
+        if ($quoted) {
+            $tablename = $this->getEncQuoted($tablename);
+        }
+
+        return $tablename;
+    }
+
+    /**
+     * Given one correct XMLDBTable, returns the SQL statements
+     * to create it (inside one array)
+     */
+    public function getCreateTableSQL($xmldb_table) {
+
+        $results = array();  //Array where all the sentences will be stored
+
+    /// Table header
+        $table = 'CREATE TABLE ' . $this->getTableName($xmldb_table) . ' (';
+
+        if (!$xmldb_fields = $xmldb_table->getFields()) {
+            return $results;
+        }
+
+    /// Add the fields, separated by commas
+        foreach ($xmldb_fields as $xmldb_field) {
+            $table .= "\n    " . $this->getFieldSQL($xmldb_field);
+            $table .= ',';
+        }
+    /// Add the keys, separated by commas
+        if ($xmldb_keys = $xmldb_table->getKeys()) {
+            foreach ($xmldb_keys as $xmldb_key) {
+                if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) {
+                    $table .= "\nCONSTRAINT " . $keytext . ',';
+                }
+            /// If the key is XMLDB_KEY_FOREIGN_UNIQUE, create it as UNIQUE too
+                if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE) {
+                ///Duplicate the key
+                    $xmldb_key->setType(XMLDB_KEY_UNIQUE);
+                    if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) {
+                        $table .= "\nCONSTRAINT " . $keytext . ',';
+                    }
+                }
+            }
+        }
+    /// Add enum extra code if needed
+        if ($this->enum_extra_code) {
+        /// Iterate over fields looking for enums
+            foreach ($xmldb_fields as $xmldb_field) {
+                if ($xmldb_field->getEnum()) {
+                    $table .= "\n" . $this->getEnumExtraSQL($xmldb_table, $xmldb_field) . ',';
+                }
+            }
+        }
+    /// Table footer, trim the latest comma
+        $table = trim($table,',');
+        $table .= "\n)";
+
+    /// Add the CREATE TABLE to results
+        $results[] = $table;
+
+    /// Add comments if specified and it exists
+        if ($this->add_table_comments && $xmldb_table->getComment()) {
+            $comment = $this->getCommentSQL($xmldb_table);
+        /// Add the COMMENT to results
+            $results = array_merge($results, $comment);
+        }
+
+    /// Add the indexes (each one, one statement)
+        if ($xmldb_indexes = $xmldb_table->getIndexes()) {
+            foreach ($xmldb_indexes as $xmldb_index) {
+            ///Only process all this if the index doesn't exist in DB
+                if (!$this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) {
+                    if ($indextext = $this->getCreateIndexSQL($xmldb_table, $xmldb_index)) {
+                        $results = array_merge($results, $indextext);
+                    }
+                }
+            }
+        }
+
+    /// Also, add the indexes needed from keys, based on configuration (each one, one statement)
+        if ($xmldb_keys = $xmldb_table->getKeys()) {
+            foreach ($xmldb_keys as $xmldb_key) {
+            /// If we aren't creating the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated
+            /// automatically by the RDBMS) create the underlying (created by us) index (if doesn't exists)
+                if (!$this->getKeySQL($xmldb_table, $xmldb_key) || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
+                /// Create the interim index
+                    $index = new XMLDBIndex('anyname');
+                    $index->setFields($xmldb_key->getFields());
+                ///Only process all this if the index doesn't exist in DB
+                    if (!$this->mdb->get_manager()->index_exists($xmldb_table, $index)) {
+                        $createindex = false; //By default
+                        switch ($xmldb_key->getType()) {
+                            case XMLDB_KEY_UNIQUE:
+                            case XMLDB_KEY_FOREIGN_UNIQUE:
+                                $index->setUnique(true);
+                                $createindex = true;
+                                break;
+                            case XMLDB_KEY_FOREIGN:
+                                $index->setUnique(false);
+                                $createindex = true;
+                                break;
+                        }
+                        if ($createindex) {
+                            if ($indextext = $this->getCreateIndexSQL($xmldb_table, $index)) {
+                            /// Add the INDEX to the array
+                                $results = array_merge($results, $indextext);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+    /// Add sequence extra code if needed
+        if ($this->sequence_extra_code) {
+        /// Iterate over fields looking for sequences
+            foreach ($xmldb_fields as $xmldb_field) {
+                if ($xmldb_field->getSequence()) {
+                /// returns an array of statements needed to create one sequence
+                    $sequence_sentences = $this->getCreateSequenceSQL($xmldb_table, $xmldb_field);
+                /// Add the SEQUENCE to the array
+                    $results = array_merge($results, $sequence_sentences);
+                }
+            }
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one correct XMLDBIndex, returns the SQL statements
+     * needed to create it (in array)
+     */
+    public function getCreateIndexSQL($xmldb_table, $xmldb_index) {
+
+        $unique = '';
+        $suffix = 'ix';
+        if ($xmldb_index->getUnique()) {
+            $unique = ' UNIQUE';
+            $suffix = 'uix';
+        }
+
+        $index = 'CREATE' . $unique . ' INDEX ';
+        $index .= $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_index->getFields()), $suffix);
+        $index .= ' ON ' . $this->getTableName($xmldb_table);
+        $index .= ' (' . implode(', ', $this->getEncQuoted($xmldb_index->getFields())) . ')';
+
+        return array($index);
+    }
+
+    /**
+     * Given one correct XMLDBField, returns the complete SQL line to create it
+     */
+    public function getFieldSQL($xmldb_field, $skip_type_clause = false, $skip_default_clause = false, $skip_notnull_clause = false)  {
+
+    /// First of all, convert integers to numbers if defined
+        if ($this->integer_to_number) {
+            if ($xmldb_field->getType() == XMLDB_TYPE_INTEGER) {
+                $xmldb_field->setType(XMLDB_TYPE_NUMBER);
+            }
+        }
+    /// Same for floats
+        if ($this->float_to_number) {
+            if ($xmldb_field->getType() == XMLDB_TYPE_FLOAT) {
+                $xmldb_field->setType(XMLDB_TYPE_NUMBER);
+            }
+        }
+
+    /// The name
+        $field = $this->getEncQuoted($xmldb_field->getName());
+    /// The type and length only if we don't want to skip it
+        if (!$skip_type_clause) {
+        /// The type and length (if the field isn't enum)
+            if (!$xmldb_field->getEnum() || $this->enum_inline_code == false) {
+                $field .= ' ' . $this->getTypeSQL($xmldb_field->getType(), $xmldb_field->getLength(), $xmldb_field->getDecimals());
+            } else {
+            /// call to custom function
+                $field .= ' ' . $this->getEnumSQL($xmldb_field);
+            }
+        }
+    /// The unsigned if supported
+        if ($this->unsigned_allowed && ($xmldb_field->getType() == XMLDB_TYPE_INTEGER ||
+                                      $xmldb_field->getType() == XMLDB_TYPE_NUMBER ||
+                                      $xmldb_field->getType() == XMLDB_TYPE_FLOAT)) {
+            if ($xmldb_field->getUnsigned()) {
+                $field .= ' unsigned';
+            }
+        }
+    /// Calculate the not null clause
+        $notnull = '';
+    /// Only if we don't want to skip it
+        if (!$skip_notnull_clause) {
+            if ($xmldb_field->getNotNull()) {
+                $notnull = ' NOT NULL';
+            } else {
+                if ($this->specify_nulls) {
+                    $notnull = ' NULL';
+                }
+            }
+        }
+    /// Calculate the default clause
+        $default_clause = '';
+        if (!$skip_default_clause) { //Only if we don't want to skip it
+            $default_clause = $this->getDefaultClause($xmldb_field);
+        }
+    /// Based on default_after_null, set both clauses properly
+        if ($this->default_after_null) {
+            $field .= $notnull . $default_clause;
+        } else {
+            $field .= $default_clause . $notnull;
+        }
+    /// The sequence
+        if ($xmldb_field->getSequence()) {
+            if($xmldb_field->getLength()<=9 && $this->sequence_name_small) {
+                $sequencename=$this->sequence_name_small;
+            } else {
+                $sequencename=$this->sequence_name;
+            }
+            $field .= ' ' . $sequencename;
+            if ($this->sequence_only) {
+            /// We only want the field name and sequence name to be printed
+            /// so, calculate it and return
+                $sql = $this->getEncQuoted($xmldb_field->getName()) . ' ' . $sequencename;
+                return $sql;
+            }
+        }
+        return $field;
+    }
+
+    /**
+     * Given one correct XMLDBKey, returns its specs
+     */
+    public function getKeySQL($xmldb_table, $xmldb_key) {
+
+        $key = '';
+
+        switch ($xmldb_key->getType()) {
+            case XMLDB_KEY_PRIMARY:
+                if ($this->primary_keys) {
+                    if ($this->primary_key_name !== null) {
+                        $key = $this->getEncQuoted($this->primary_key_name);
+                    } else {
+                        $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'pk');
+                    }
+                    $key .= ' PRIMARY KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')';
+                }
+                break;
+            case XMLDB_KEY_UNIQUE:
+                if ($this->unique_keys) {
+                    $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'uk');
+                    $key .= ' UNIQUE (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')';
+                }
+                break;
+            case XMLDB_KEY_FOREIGN:
+            case XMLDB_KEY_FOREIGN_UNIQUE:
+                if ($this->foreign_keys) {
+                    $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'fk');
+                    $key .= ' FOREIGN KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')';
+                    $key .= ' REFERENCES ' . $this->getEncQuoted($this->prefix . $xmldb_key->getRefTable());
+                    $key .= ' (' . implode(', ', $this->getEncQuoted($xmldb_key->getRefFields())) . ')';
+                }
+                break;
+        }
+
+        return $key;
+    }
+
+    /**
+     * Give one XMLDBField, returns the correct "default value" for the current configuration
+     */
+    public function getDefaultValue($xmldb_field) {
+
+        $default = null;
+
+        if ($xmldb_field->getDefault() !== NULL) {
+            if ($xmldb_field->getType() == XMLDB_TYPE_CHAR ||
+                $xmldb_field->getType() == XMLDB_TYPE_TEXT) {
+                    $default = "'" . $this->addslashes($xmldb_field->getDefault()) . "'";
+            } else {
+                $default = $xmldb_field->getDefault();
+            }
+        } else {
+        /// We force default '' for not null char columns without proper default
+        /// some day this should be out!
+            if ($this->default_for_char !== NULL &&
+                $xmldb_field->getType() == XMLDB_TYPE_CHAR &&
+                $xmldb_field->getNotNull()) {
+                $default = "'" . $this->default_for_char . "'";
+            } else {
+            /// If the DB requires to explicity define some clause to drop one default, do it here
+            /// never applying defaults to TEXT and BINARY fields
+                if ($this->drop_default_value_required &&
+                    $xmldb_field->getType() != XMLDB_TYPE_TEXT &&
+                    $xmldb_field->getType() != XMLDB_TYPE_BINARY && !$xmldb_field->getNotNull()) {
+                    $default = $this->drop_default_value;
+                }
+            }
+        }
+        return $default;
+    }
+
+    /**
+     * Given one XMLDBField, returns the correct "default clause" for the current configuration
+     */
+    public function getDefaultClause($xmldb_field) {
+
+        $defaultvalue = $this->getDefaultValue ($xmldb_field);
+
+        if ($defaultvalue !== null) {
+            return ' DEFAULT ' . $defaultvalue;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Given one correct XMLDBTable and the new name, returns the SQL statements
+     * to rename it (inside one array)
+     */
+    public function getRenameTableSQL($xmldb_table, $newname) {
+
+        $results = array();  //Array where all the sentences will be stored
+
+        $newt = new XMLDBTable($newname); //Temporal table for name calculations
+
+        $rename = str_replace('OLDNAME', $this->getTableName($xmldb_table), $this->rename_table_sql);
+        $rename = str_replace('NEWNAME', $this->getTableName($newt), $rename);
+
+        $results[] = $rename;
+
+    /// Call to getRenameTableExtraSQL() override if needed
+        $extra_sentences = $this->getRenameTableExtraSQL($xmldb_table, $newname);
+        $results = array_merge($results, $extra_sentences);
+
+        return $results;
+    }
+
+    /**
+     * Given one correct XMLDBTable and the new name, returns the SQL statements
+     * to drop it (inside one array)
+     */
+    public function getDropTableSQL($xmldb_table) {
+
+        $results = array();  //Array where all the sentences will be stored
+
+        $drop = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->drop_table_sql);
+
+        $results[] = $drop;
+
+    /// call to getDropTableExtraSQL(), override if needed
+        $extra_sentences = $this->getDropTableExtraSQL($xmldb_table);
+        $results = array_merge($results, $extra_sentences);
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add the field to the table
+     */
+    public function getAddFieldSQL($xmldb_table, $xmldb_field) {
+
+        $results = array();
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+
+    /// Build the standard alter table add
+        $sql = $this->getFieldSQL($xmldb_field, $this->alter_column_skip_type,
+                                  $this->alter_column_skip_default,
+                                  $this->alter_column_skip_notnull);
+        $altertable = 'ALTER TABLE ' . $tablename . ' ADD ' . $sql;
+    /// Add the after clause if necesary
+        if ($this->add_after_clause && $xmldb_field->getPrevious()) {
+            $altertable .= ' AFTER ' . $this->getEncQuoted($xmldb_field->getPrevious());
+        }
+        $results[] = $altertable;
+
+    /// If the DB has extra enum code
+        if ($this->enum_extra_code) {
+        /// If it's enum add the extra code
+            if ($xmldb_field->getEnum()) {
+                $results[] = 'ALTER TABLE ' . $tablename . ' ADD ' . $this->getEnumExtraSQL($xmldb_table, $xmldb_field);
+            }
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop the field from the table
+     */
+    public function getDropFieldSQL($xmldb_table, $xmldb_field) {
+
+        $results = array();
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// Build the standard alter table drop
+        $results[] = 'ALTER TABLE ' . $tablename . ' DROP COLUMN ' . $fieldname;
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table
+     */
+    public function getAlterFieldSQL($xmldb_table, $xmldb_field) {
+
+        $results = array();
+
+    /// Always specify NULLs in alter fields because we can change not nulls to nulls
+        $this->specify_nulls = true;
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// Build de alter sentence using the alter_column_sql template
+        $alter = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->alter_column_sql);
+        $colspec = $this->getFieldSQL($xmldb_field, $this->alter_column_skip_type,
+                                      $this->alter_column_skip_default,
+                                      $this->alter_column_skip_notnull);
+        $alter = str_replace('COLUMNSPECS', $colspec, $alter);
+
+    /// Add the after clause if necesary
+        if ($this->add_after_clause && $xmldb_field->getPrevious()) {
+            $alter .= ' after ' . $this->getEncQuoted($xmldb_field->getPrevious());
+        }
+
+    /// Build the standard alter table modify
+        $results[] = $alter;
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to modify the enum of the field in the table
+     */
+    public function getModifyEnumSQL($xmldb_table, $xmldb_field) {
+
+        $results = array();
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// Decide if we are going to create or to drop the enum (based exclusively in the values passed!)
+        if (!$xmldb_field->getEnum()) {
+            $results = $this->getDropEnumSQL($xmldb_table, $xmldb_field); //Drop
+        } else {
+            $results = $this->getCreateEnumSQL($xmldb_table, $xmldb_field); //Create/modify
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to modify the default of the field in the table
+     */
+    public function getModifyDefaultSQL($xmldb_table, $xmldb_field) {
+
+        $results = array();
+
+    /// Get the quoted name of the table and field
+        $tablename = $this->getTableName($xmldb_table);
+        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+
+    /// Decide if we are going to create/modify or to drop the default
+        if ($xmldb_field->getDefault() === null) {
+            $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop
+        } else {
+            $results = $this->getCreateDefaultSQL($xmldb_table, $xmldb_field); //Create/modify
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one correct XMLDBField and the new name, returns the SQL statements
+     * to rename it (inside one array)
+     */
+    public function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
+
+        $results = array();  //Array where all the sentences will be stored
+
+    /// Although this is checked in ddllib - rename_field() - double check
+    /// that we aren't trying to rename one "id" field. Although it could be
+    /// implemented (if adding the necessary code to rename sequences, defaults,
+    /// triggers... and so on under each getRenameFieldExtraSQL() function, it's
+    /// better to forbide it, mainly because this field is the default PK and
+    /// in the future, a lot of FKs can be pointing here. So, this field, more
+    /// or less, must be considered inmutable!
+        if ($xmldb_field->getName() == 'id') {
+            return array();
+        }
+
+        $rename = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_column_sql);
+        $rename = str_replace('OLDFIELDNAME', $this->getEncQuoted($xmldb_field->getName()), $rename);
+        $rename = str_replace('NEWFIELDNAME', $this->getEncQuoted($newname), $rename);
+
+        $results[] = $rename;
+
+    /// Call to getRenameFieldExtraSQL(), override if needed
+        $extra_sentences = $this->getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname);
+        $results = array_merge($results, $extra_sentences);
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBKey, return the SQL statements needded to add the key to the table
+     * note that undelying indexes will be added as parametrised by $xxxx_keys and $xxxx_index parameters
+     */
+    public function getAddKeySQL($xmldb_table, $xmldb_key) {
+
+        $results = array();
+
+    /// Just use the CreateKeySQL function
+        if ($keyclause = $this->getKeySQL($xmldb_table, $xmldb_key)) {
+            $key = 'ALTER TABLE ' . $this->getTableName($xmldb_table) .
+               ' ADD CONSTRAINT ' . $keyclause;
+            $results[] = $key;
+        }
+
+    /// If we aren't creating the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated
+    /// automatically by the RDBMS) create the underlying (created by us) index (if doesn't exists)
+        if (!$keyclause || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
+        /// Only if they don't exist
+            if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN) {  ///Calculate type of index based on type ok key
+                $indextype = XMLDB_INDEX_NOTUNIQUE;
+            } else {
+                $indextype = XMLDB_INDEX_UNIQUE;
+            }
+            $xmldb_index = new XMLDBIndex('anyname');
+            $xmldb_index->setAttributes($indextype, $xmldb_key->getFields());
+            if (!$this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) {
+                $results = array_merge($results, $this->getAddIndexSQL($xmldb_table, $xmldb_index));
+            }
+        }
+
+    /// If the key is XMLDB_KEY_FOREIGN_UNIQUE, create it as UNIQUE too
+        if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && $this->unique_keys) {
+        ///Duplicate the key
+            $xmldb_key->setType(XMLDB_KEY_UNIQUE);
+            $results = array_merge($results, $this->getAddKeySQL($xmldb_table, $xmldb_key));
+        }
+
+    /// Return results
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to drop the index from the table
+     */
+    public function getDropKeySQL($xmldb_table, $xmldb_key) {
+
+        $results = array();
+
+    /// Get the key name (note that this doesn't introspect DB, so could cause some problems sometimes!)
+    /// TODO: We'll need to overwrite the whole getDropKeySQL() method inside each DB to do the proper queries
+    /// against the dictionary or require ADOdb to support it or change the find_key_name() method to
+    /// perform DB introspection directly. But, for now, as we aren't going to enable referential integrity
+    /// it won't be a problem at all
+        $dbkeyname = $this->mdb->get_manager()->find_key_name($xmldb_table, $xmldb_key);
+
+    /// Only if such type of key generation is enabled
+        $dropkey = false;
+        switch ($xmldb_key->getType()) {
+            case XMLDB_KEY_PRIMARY:
+                if ($this->primary_keys) {
+                    $template = $this->drop_primary_key;
+                    $dropkey = true;
+                }
+                break;
+            case XMLDB_KEY_UNIQUE:
+                if ($this->unique_keys) {
+                    $template = $this->drop_unique_key;
+                    $dropkey = true;
+                }
+                break;
+            case XMLDB_KEY_FOREIGN_UNIQUE:
+            case XMLDB_KEY_FOREIGN:
+                if ($this->foreign_keys) {
+                    $template = $this->drop_foreign_key;
+                    $dropkey = true;
+                }
+                break;
+        }
+    /// If we have decided to drop the key, let's do it
+        if ($dropkey) {
+        /// Replace TABLENAME, CONSTRAINTTYPE and KEYNAME as needed
+            $dropsql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $template);
+            $dropsql = str_replace('KEYNAME', $dbkeyname, $dropsql);
+
+            $results[] = $dropsql;
+        }
+
+    /// If we aren't dropping the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated
+    /// automatically by the RDBMS) drop the underlying (created by us) index (if exists)
+        if (!$dropkey || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) {
+        /// Only if they exist
+            $xmldb_index = new XMLDBIndex('anyname');
+            $xmldb_index->setAttributes(XMLDB_INDEX_UNIQUE, $xmldb_key->getFields());
+            if ($this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) {
+                $results = array_merge($results, $this->getDropIndexSQL($xmldb_table, $xmldb_index));
+            }
+        }
+
+    /// If the key is XMLDB_KEY_FOREIGN_UNIQUE, drop the UNIQUE too
+        if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && $this->unique_keys) {
+        ///Duplicate the key
+            $xmldb_key->setType(XMLDB_KEY_UNIQUE);
+            $results = array_merge($results, $this->getDropKeySQL($xmldb_table, $xmldb_key));
+        }
+
+    /// Return results
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBKey, return the SQL statements needded to rename the key in the table
+     * Experimental! Shouldn't be used at all!
+     */
+
+    public function getRenameKeySQL($xmldb_table, $xmldb_key, $newname) {
+
+        $results = array();
+
+    /// Get the real key name
+        $dbkeyname = $this->mdb->get_manager()->find_key_name($xmldb_table, $xmldb_key);
+
+    /// Check we are really generating this type of keys
+        if (($xmldb_key->getType() == XMLDB_KEY_PRIMARY && !$this->primary_keys) ||
+            ($xmldb_key->getType() == XMLDB_KEY_UNIQUE && !$this->unique_keys) ||
+            ($xmldb_key->getType() == XMLDB_KEY_FOREIGN && !$this->foreign_keys) ||
+            ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && !$this->unique_keys && !$this->foreign_keys)) {
+        /// We aren't generating this type of keys, delegate to child indexes
+            $xmldb_index = new XMLDBIndex($xmldb_key->getName());
+            $xmldb_index->setFields($xmldb_key->getFields());
+            return $this->getRenameIndexSQL($xmldb_table, $xmldb_index, $newname);
+        }
+
+    /// Arrived here so we are working with keys, lets rename them
+    /// Replace TABLENAME and KEYNAME as needed
+        $renamesql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_key_sql);
+        $renamesql = str_replace('OLDKEYNAME', $dbkeyname, $renamesql);
+        $renamesql = str_replace('NEWKEYNAME', $newname, $renamesql);
+
+    /// Some DB doesn't support key renaming so this can be empty
+        if ($renamesql) {
+            $results[] = $renamesql;
+        }
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to add the index to the table
+     */
+    public function getAddIndexSQL($xmldb_table, $xmldb_index) {
+
+    /// Just use the CreateIndexSQL function
+        return $this->getCreateIndexSQL($xmldb_table, $xmldb_index);
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to drop the index from the table
+     */
+    public function getDropIndexSQL($xmldb_table, $xmldb_index) {
+
+        $results = array();
+
+    /// Get the real index name
+        $dbindexname = $this->mdb->get_manager()->find_index_name($xmldb_table, $xmldb_index);
+
+    /// Replace TABLENAME and INDEXNAME as needed
+        $dropsql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->drop_index_sql);
+        $dropsql = str_replace('INDEXNAME', $dbindexname, $dropsql);
+
+        $results[] = $dropsql;
+
+        return $results;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to rename the index in the table
+     * Experimental! Shouldn't be used at all!
+     */
+    function getRenameIndexSQL($xmldb_table, $xmldb_index, $newname) {
+    /// Some DB doesn't support index renaming (MySQL) so this can be empty
+        if (empty($this->rename_index_sql)) {
+            return array();
+        }
+
+    /// Get the real index name
+        $dbindexname = find_index_name($xmldb_table, $xmldb_index);
+    /// Replace TABLENAME and INDEXNAME as needed
+        $renamesql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_index_sql);
+        $renamesql = str_replace('OLDINDEXNAME', $dbindexname, $renamesql);
+        $renamesql = str_replace('NEWINDEXNAME', $newname, $renamesql);
+
+        return array($renamesql);
+    }
+
+    /**
+     * Given three strings (table name, list of fields (comma separated) and suffix),
+     * create the proper object name quoting it if necessary.
+     *
+     * IMPORTANT: This function must be used to CALCULATE NAMES of objects TO BE CREATED,
+     *            NEVER TO GUESS NAMES of EXISTING objects!!!
+     */
+    public function getNameForObject($tablename, $fields, $suffix='') {
+
+        $name = '';
+
+    /// Implement one basic cache to avoid object name duplication
+    /// and to speed up repeated queries for the same objects
+        if (!isset($used_names)) {
+            static $used_names = array();
+        }
+
+    /// If this exact object has been requested, return it
+        if (array_key_exists($tablename.'-'.$fields.'-'.$suffix, $used_names)) {
+            return $used_names[$tablename.'-'.$fields.'-'.$suffix];
+        }
+
+    /// Use standard naming. See http://docs.moodle.org/en/XMLDB_key_and_index_naming
+        $tablearr = explode ('_', $tablename);
+        foreach ($tablearr as $table) {
+            $name .= substr(trim($table),0,4);
+        }
+        $name .= '_';
+        $fieldsarr = explode (',', $fields);
+        foreach ($fieldsarr as $field) {
+            $name .= substr(trim($field),0,3);
+        }
+    /// Prepend the prefix
+        $name = $this->prefix . $name;
+
+        $name = substr(trim($name), 0, $this->names_max_length - 1 - strlen($suffix)); //Max names_max_length
+
+    /// Add the suffix
+        $namewithsuffix = $name;
+        if ($suffix) {
+            $namewithsuffix = $namewithsuffix . '_' . $suffix;
+        }
+
+    /// If the calculated name is in the cache, or if we detect it by introspecting the DB let's modify if
+        if (in_array($namewithsuffix, $used_names) || $this->isNameInUse($namewithsuffix, $suffix, $tablename)) {
+            $counter = 2;
+        /// If have free space, we add 2
+            if (strlen($namewithsuffix) < $this->names_max_length) {
+                $newname = $name . $counter;
+        /// Else replace the last char by 2
+            } else {
+                $newname = substr($name, 0, strlen($name)-1) . $counter;
+            }
+            $newnamewithsuffix = $newname;
+            if ($suffix) {
+                $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix;
+            }
+        /// Now iterate until not used name is found, incrementing the counter
+            while (in_array($newnamewithsuffix, $used_names) || $this->isNameInUse($newnamewithsuffix, $suffix, $tablename)) {
+                $counter++;
+                $newname = substr($name, 0, strlen($newname)-1) . $counter;
+                $newnamewithsuffix = $newname;
+                if ($suffix) {
+                    $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix;
+                }
+            }
+            $namewithsuffix = $newnamewithsuffix;
+        }
+
+    /// Add the name to the cache
+        $used_names[$tablename.'-'.$fields.'-'.$suffix] = $namewithsuffix;
+
+    /// Quote it if necessary (reserved words)
+        $namewithsuffix = $this->getEncQuoted($namewithsuffix);
+
+        return $namewithsuffix;
+    }
+
+    /**
+     * Given any string (or one array), enclose it by the proper quotes
+     * if it's a reserved word
+     */
+    public function getEncQuoted($input) {
+
+        if (is_array($input)) {
+            foreach ($input as $key=>$content) {
+                $input[$key] = $this->getEncQuoted($content);
+            }
+            return $input;
+        } else {
+        /// Always lowercase
+            $input = strtolower($input);
+        /// if reserved or quote_all, quote it
+            if ($this->quote_all || in_array($input, $this->reserved_words)) {
+                $input = $this->quote_string . $input . $this->quote_string;
+            }
+            return $input;
+        }
+    }
+
+    /**
+     * Given one XMLDB Statement, build the needed SQL insert sentences to execute it
+     */
+    function getExecuteInsertSQL($statement) {
+
+         $results = array();  //Array where all the sentences will be stored
+
+         if ($sentences = $statement->getSentences()) {
+             foreach ($sentences as $sentence) {
+             /// Get the list of fields
+                 $fields = $statement->getFieldsFromInsertSentence($sentence);
+             /// Get the values of fields
+                 $values = $statement->getValuesFromInsertSentence($sentence);
+             /// Look if we have some CONCAT value and transform it dinamically
+                 foreach($values as $key => $value) {
+                 /// Trim single quotes
+                     $value = trim($value,"'");
+                     if (stristr($value, 'CONCAT') !== false){
+                     /// Look for data between parentesis
+                         preg_match("/CONCAT\s*\((.*)\)$/is", trim($value), $matches);
+                         if (isset($matches[1])) {
+                             $part = $matches[1];
+                         /// Convert the comma separated string to an array
+                             $arr = XMLDBObject::comma2array($part);
+                             if ($arr) {
+                                 $value = $this->getConcatSQL($arr);
+                             }
+                         }
+                     }
+                 /// Values to be sent to DB must be properly escaped
+                     $value = $this->addslashes($value);
+                 /// Back trimmed quotes
+                     $value = "'" . $value . "'";
+                 /// Back to the array
+                     $values[$key] = $value;
+                 }
+
+             /// Iterate over fields, escaping them if necessary
+                 foreach($fields as $key => $field) {
+                     $fields[$key] = $this->getEncQuoted($field);
+                 }
+             /// Build the final SQL sentence and add it to the array of results
+             $sql = 'INSERT INTO ' . $this->getEncQuoted($this->prefix . $statement->getTable()) .
+                         '(' . implode(', ', $fields) . ') ' .
+                         'VALUES (' . implode(', ', $values) . ')';
+                 $results[] = $sql;
+             }
+
+         }
+         return $results;
+    }
+
+    /**
+     * Given one array of elements, build de proper CONCAT expresion, based
+     * in the $concat_character setting. If such setting is empty, then
+     * MySQL's CONCAT function will be used instead
+     */
+    public function getConcatSQL($elements) {
+
+    /// Replace double quoted elements by single quotes
+        foreach($elements as $key => $element) {
+            $element = trim($element);
+            if (substr($element, 0, 1) == '"' &&
+                substr($element, -1, 1) == '"') {
+                    $elements[$key] = "'" . trim($element, '"') . "'";
+            }
+        }
+
+    /// Now call the standard sql_concat() DML function
+        return call_user_func_array(array($this->mdb, 'sql_concat'), $elements);
+    }
+
+    /**
+     * Returns the name (string) of the sequence used in the table for the autonumeric pk
+     * Only some DB have this implemented
+     */
+    public function getSequenceFromDB($xmldb_table) {
+        return false;
+    }
+
+    /**
+     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
+     * return if such name is currently in use (true) or no (false)
+     * (MySQL requires the whole XMLDBTable object to be specified, so we add it always)
+     * (invoked from getNameForObject()
+     * Only some DB have this implemented
+     */
+    public function isNameInUse($object_name, $type, $table_name) {
+        return false; //For generators not implementing introspecion,
+                      //we always return with the name being free to be used
+    }
+
+
+/// ALL THESE FUNCTION MUST BE CUSTOMISED BY ALL THE XMLDGenerator classes
+
+    /**
+     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
+     */
+    public abstract function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null);
+
+    /**
+     * Given one XMLDB Field, return its enum SQL to be added inline with the column definition
+     */
+    public function getEnumSQL($xmldb_field) {
+        return '';
+    }
+
+    /**
+     * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
+     */
+    public function getEnumExtraSQL($xmldb_table, $xmldb_field) {
+        return '';
+    }
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on field rename
+     */
+    public function getRenameFieldExtraSQL($xmldb_table, $xmldb_field) {
+        return array();
+    }
+
+    /**
+     * Returns the code (array of statements) needed
+     * to create one sequence for the xmldb_table and xmldb_field passes
+     */
+    public function getCreateSequenceSQL($xmldb_table, $xmldb_field) {
+        return array();
+    }
+
+    /**
+     * Returns the code (array of statements) needed to add one comment to the table
+     */
+    public abstract function getCommentSQL($xmldb_table);
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on table rename
+     */
+    public function getRenameTableExtraSQL($xmldb_table) {
+        return array();
+    }
+
+    /**
+     * Returns the code (array of statements) needed to execute extra statements on table drop
+     */
+    public function getDropTableExtraSQL($xmldb_table) {
+        return array();
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public abstract function getDropEnumSQL($xmldb_table, $xmldb_field);
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public abstract function getCreateEnumSQL($xmldb_table, $xmldb_field);
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public abstract function getDropDefaultSQL($xmldb_table, $xmldb_field);
+
+    /**
+     * Given one XMLDBTable and one optional XMLDBField, return one array with all the check
+     * constrainst found for that table (or field). Must exist for each DB supported.
+     * (usually invoked from find_check_constraint_name)
+     */
+    public abstract function getCheckConstraintsFromDB($xmldb_table, $xmldb_field=null);
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public abstract function getCreateDefaultSQL($xmldb_table, $xmldb_field);
+
+    /**
+     * Returns an array of reserved words (lowercase) for this DB
+     * You MUST provide the real list for each DB inside every XMLDB class
+     */
+    public static abstract function getReservedWords();
+
+    /**
+     * Returns all reserved works in supported databases.
+     * @return array ('word'=>array(databases))
+     */
+    public static function getAllReservedWords() {
+        global $CFG;
+
+        $reserved_words = array();
+
+        require("$CFG->libdir/ddl/mysql_sql_generator.php");
+        require("$CFG->libdir/ddl/postgres_sql_generator.php");
+        require("$CFG->libdir/ddl/oracle_sql_generator.php");
+        require("$CFG->libdir/ddl/mssql_sql_generator.php");
+
+        foreach (mysql_sql_generator::getReservedWords() as $word) {
+            if (!isset($reserved_words[$word])) {
+                $reserved_words[$word] = array();
+            }
+            $reserved_words[$word][] = 'mysql';
+        }
+        foreach (postgres_sql_generator::getReservedWords() as $word) {
+            if (!isset($reserved_words[$word])) {
+                $reserved_words[$word] = array();
+            }
+            $reserved_words[$word][] = 'postgres';
+        }
+        foreach (oracle_sql_generator::getReservedWords() as $word) {
+            if (!isset($reserved_words[$word])) {
+                $reserved_words[$word] = array();
+            }
+            $reserved_words[$word][] = 'oracle';
+        }
+        foreach (mssql_sql_generator::getReservedWords() as $word) {
+            if (!isset($reserved_words[$word])) {
+                $reserved_words[$word] = array();
+            }
+            $reserved_words[$word][] = 'mssql';
+        }
+        ksort($reserved_words);
+        return $reserved_words;
+    }
+
+    public function addslashes($s) {
+        // do not use php addslashes() because it depends on PHP quote settings!
+        $s = str_replace('\\','\\\\',$s);
+        $s = str_replace("\0","\\\0", $s);
+        $s = str_replace("'",  "\\'", $s);
+        return $s;
+    }
+}
+
+?>
Index: lib/dml/oci8po_adodb_moodle_database.php
===================================================================
RCS file: lib/dml/oci8po_adodb_moodle_database.php
diff -N lib/dml/oci8po_adodb_moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/oci8po_adodb_moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,483 @@
+<?php  //$Id:$
+
+require_once($CFG->libdir.'/dml/moodle_database.php');
+require_once($CFG->libdir.'/dml/adodb_moodle_database.php');
+require_once($CFG->libdir.'/dml/oci8po_adodb_moodle_recordset.php');
+
+/**
+ * Oracle database class using adodb backend
+ * @package dmlib
+ */
+class oci8_adodb_moodle_database extends adodb_moodle_database {
+    function __construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        if ($prefix=='') {
+            print_error('prefixcannotbeempty', 'debug', '', array($prefix, $this->get_dbfamily()));
+        }
+        if (strlen($prefix) > 2) { //Max prefix length for Oracle is 2cc
+            print_error('prefixlimit', 'debug', '', $prefix);
+        }
+
+        parent::__construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix);
+    }
+
+    protected function configure_dbconnection() {
+        if (!defined('ADODB_ASSOC_CASE')) {
+            define ('ADODB_ASSOC_CASE', 0); /// Use lowercase fieldnames for ADODB_FETCH_ASSOC
+                                            /// (only meaningful for oci8po, it's the default
+                                            /// for other DB drivers so this won't affect them)
+        }
+        /// Row prefetching uses a bit of memory but saves a ton
+        /// of network latency. With current AdoDB and PHP, only
+        /// Oracle uses this setting.
+        if (!defined('ADODB_PREFETCH_ROWS')) {
+            define ('ADODB_PREFETCH_ROWS', 1000);
+        }
+        $this->db->SetFetchMode(ADODB_ASSOC_CASE);
+
+        /// No need to set charset. It must be specified by the NLS_LANG env. variable
+        /// Enable sybase quotes, so addslashes and stripslashes will use "'"
+            ini_set('magic_quotes_sybase', '1');
+        /// NOTE: Not 100% useful because GPC has been addslashed with the setting off
+        ///       so IT'S MANDATORY TO ENABLE THIS UNDER php.ini or .htaccess for this DB
+        ///       or to turn off magic_quotes to allow Moodle to do it properly
+        /// Now set the decimal separator to DOT, Moodle & PHP will always send floats to
+        /// DB using DOTS. Manually introduced floats (if using other characters) must be
+        /// converted back to DOTs (like gradebook does)
+            $this->db->Execute("ALTER SESSION SET NLS_NUMERIC_CHARACTERS='.,'");
+
+        return true;
+    }
+
+    /**
+     * Returns database family type
+     * @return string db family name (mysql, postgres, mssql, oracle, etc.)
+     */
+    public function get_dbfamily() {
+        return 'oracle';
+    }
+
+    /**
+     * Returns database type
+     * @return string db type mysql, mysqli, postgres7
+     */
+    protected function get_dbtype() {
+        return 'oci8po';
+    }
+
+    /**
+     * Returns supported query parameter types
+     * @return bitmask
+     */
+    protected function allowed_param_types() {
+        return SQL_PARAMS_NAMED;
+    }
+
+    /**
+     * This method will introspect inside DB to detect it it's a UTF-8 DB or no
+     * Used from setup.php to set correctly "set names" when the installation
+     * process is performed without the initial and beautiful installer
+     * @return bool true if db in unicode mode
+     */
+    function setup_is_unicodedb() {
+        $rs = $this->db->Execute("SELECT parameter, value FROM nls_database_parameters where parameter = 'NLS_CHARACTERSET'");
+        if ($rs && !$rs->EOF) {
+            $encoding = $rs->fields['value'];
+            if (strtoupper($encoding) == 'AL32UTF8') {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Selects rows and return values of first column as array.
+     *
+     * @param string $sql The SQL query
+     * @param array $params array of sql parameters
+     * @return mixed array of values or false if an error occured
+     */
+    public function get_fieldset_sql($sql, array $params=null) {
+        if ($result = parent::get_fieldset_sql($sql, $params)) {
+            array_walk($result, 'onespace2empty');
+        }
+        return $result;
+    }
+
+    protected function create_recordset($rs) {
+        return new oci8po_adodb_moodle_recordset($rs);
+    }
+
+    protected function adodb_recordset_to_array($rs) {
+        /// Really DIRTY HACK for Oracle - needed because it can not see difference from NULL and ''
+        /// this can not be removed even if we chane db defaults :-(
+        if ($result = parent::adodb_recordset_to_array($rs)) {
+            foreach ($result as $key=>$row) {
+                $row = (array)$row;
+                array_walk($row, 'onespace2empty');
+                $result[$key] = (object)$row;
+            }
+        }
+
+        return $result;
+    }
+
+    public function sql_bitand($int1, $int2) {
+        return 'bitand((' . $int1 . '), (' . $int2 . '))';
+    }
+
+    public function sql_bitnot($int1) {
+        return '((0 - (' . $int1 . ')) - 1)';
+    }
+
+    public function sql_bitor($int1, $int2) {
+        return '((' . $int1 . ') + (' . $int2 . ') - ' . sql_bitand($int1, $int2) . ')';
+    }
+
+    public function sql_bitxor($int1, $int2) {
+        return '((' . $int1 . ') # (' . $int2 . '))';
+    }
+
+    public function sql_cast_char2int($fieldname, $text=false) {
+        if (!$text) {
+            return ' CAST(' . $fieldname . ' AS INT) ';
+        } else {
+            return ' CAST(' . sql_compare_text($fieldname) . ' AS INT) ';
+        }
+    }
+
+    public function sql_order_by_text($fieldname, $numchars=32) {
+        return 'dbms_lob.substr(' . $fieldname . ', ' . $numchars . ',1)';
+    }
+
+    public function sql_isempty($tablename, $fieldname, $nullablefield, $textfield) {
+        if ($nullablefield) {
+            return " $fieldname IS NULL ";                    /// empties in nullable fields are stored as
+        } else {                                              /// NULLs
+            if ($textfield) {
+                return " ".sql_compare_text($fieldname)." = ' ' "; /// oracle_dirty_hack inserts 1-whitespace
+            } else {                                          /// in NOT NULL varchar and text columns so
+                return " $fieldname = ' ' ";                  /// we need to look for that in any situation
+            }
+        }
+    }
+
+    function sql_empty() {
+        return ' ';
+    }
+
+    /**
+     * Update a record in a table
+     *
+     * $dataobject is an object containing needed data
+     * Relies on $dataobject having a variable "id" to
+     * specify the record to update
+     *
+     * @param string $table The database table to be checked against.
+     * @param object $dataobject An object with contents equal to fieldname=>fieldvalue. Must have an entry for 'id' to map to the table specified.
+     * @param bool true means repeated updates expected
+     * @return bool success
+     */
+    public function update_record($table, $dataobject, $bulk=false) {
+
+error('todo');
+
+        global $db, $CFG;
+
+        if (! isset($dataobject->id) ) {
+            return false;
+        }
+
+    /// Check we are handling a proper $dataobject
+        if (is_array($dataobject)) {
+            debugging('Warning. Wrong call to update_record(). $dataobject must be an object. array found instead', DEBUG_DEVELOPER);
+            $dataobject = (object)$dataobject;
+        }
+
+    /// Temporary hack as part of phasing out all access to obsolete user tables  XXX
+        if (!empty($CFG->rolesactive)) {
+            if (in_array($table, array('user_students', 'user_teachers', 'user_coursecreators', 'user_admins'))) {
+                if (debugging()) { var_dump(debug_backtrace()); }
+                print_error('This SQL relies on obsolete tables ('.$table.')!  Your code must be fixed by a developer.');
+            }
+        }
+
+    /// Begin DIRTY HACK
+        if ($CFG->dbfamily == 'oracle') {
+            oracle_dirty_hack($table, $dataobject); // Convert object to the correct "empty" values for Oracle DB
+        }
+    /// End DIRTY HACK
+
+    /// Under Oracle, MSSQL and PostgreSQL we have our own update record process
+    /// detect all the clob/blob fields and delete them from the record being updated
+    /// saving them into $foundclobs and $foundblobs [$fieldname]->contents
+    /// They will be updated later
+        if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres')
+          && !empty($dataobject->id)) {
+        /// Detect lobs
+            $foundclobs = array();
+            $foundblobs = array();
+            db_detect_lobs($table, $dataobject, $foundclobs, $foundblobs, true);
+        }
+
+        // Determine all the fields in the table
+        if (!$columns = $db->MetaColumns($CFG->prefix . $table)) {
+            return false;
+        }
+        $data = (array)$dataobject;
+
+        if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+        // Pull out data matching these fields
+        $update = array();
+        foreach ($columns as $column) {
+            if ($column->name == 'id') {
+                continue;
+            }
+            if (array_key_exists($column->name, $data)) {
+                $key   = $column->name;
+                $value = $data[$key];
+                if (is_null($value)) {
+                    $update[] = "$key = NULL"; // previously NULLs were not updated
+                } else if (is_bool($value)) {
+                    $value = (int)$value;
+                    $update[] = "$key = $value";   // lets keep pg happy, '' is not correct smallint MDL-13038
+                } else {
+                    $update[] = "$key = '$value'"; // All incoming data is already quoted
+                }
+            }
+        }
+
+    /// Only if we have fields to be updated (this will prevent both wrong updates +
+    /// updates of only LOBs in Oracle
+        if ($update) {
+            $query = "UPDATE {$CFG->prefix}{$table} SET ".implode(',', $update)." WHERE id = {$dataobject->id}";
+            if (!$rs = $db->Execute($query)) {
+                debugging($db->ErrorMsg() .'<br /><br />'.s($query));
+                if (!empty($CFG->dblogerror)) {
+                    $debug=array_shift(debug_backtrace());
+                    error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $query");
+                }
+                return false;
+            }
+        }
+
+    /// Under Oracle, MSSQL and PostgreSQL, finally, update all the Clobs and Blobs present in the record
+    /// if we know we have some of them in the query
+        if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') &&
+            !empty($dataobject->id) &&
+            (!empty($foundclobs) || !empty($foundblobs))) {
+            if (!db_update_lobs($table, $dataobject->id, $foundclobs, $foundblobs)) {
+                return false; //Some error happened while updating LOBs
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Insert a record into a table and return the "id" field if required,
+     * Some conversions and safety checks are carried out. Lobs are supported.
+     * If the return ID isn't required, then this just reports success as true/false.
+     * $data is an object containing needed data
+     * @param string $table The database table to be inserted into
+     * @param object $data A data object with values for one or more fields in the record
+     * @param bool $returnid Should the id of the newly created record entry be returned? If this option is not requested then true/false is returned.
+     * @param bool $bulk true means repeated inserts expected
+     * @return mixed success or new ID
+     */
+    public function insert_record($table, $dataobject, $returnid=true, $bulk=false) {
+error('todo');
+
+    ///////////////////////////////////////////////////////////////
+    /// TODO: keeping this for now - only mysql implemented ;-) ///
+    ///////////////////////////////////////////////////////////////
+
+        global $db, $CFG, $empty_rs_cache;
+
+        if (empty($db)) {
+            return false;
+        }
+
+    /// Check we are handling a proper $dataobject
+        if (is_array($dataobject)) {
+            debugging('Warning. Wrong call to insert_record(). $dataobject must be an object. array found instead', DEBUG_DEVELOPER);
+            $dataobject = (object)$dataobject;
+        }
+
+    /// Temporary hack as part of phasing out all access to obsolete user tables  XXX
+        if (!empty($CFG->rolesactive)) {
+            if (in_array($table, array('user_students', 'user_teachers', 'user_coursecreators', 'user_admins'))) {
+                if (debugging()) { var_dump(debug_backtrace()); }
+                print_error('This SQL relies on obsolete tables ('.$table.')!  Your code must be fixed by a developer.');
+            }
+        }
+
+        if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+
+    /// In Moodle we always use auto-numbering fields for the primary key
+    /// so let's unset it now before it causes any trouble later
+        unset($dataobject->{$primarykey});
+
+    /// Get an empty recordset. Cache for multiple inserts.
+        if (empty($empty_rs_cache[$table])) {
+            /// Execute a dummy query to get an empty recordset
+            if (!$empty_rs_cache[$table] = $db->Execute('SELECT * FROM '. $CFG->prefix . $table .' WHERE '. $primarykey  .' = \'-1\'')) {
+                return false;
+            }
+        }
+
+        $rs = $empty_rs_cache[$table];
+
+    /// Postgres doesn't have the concept of primary key built in
+    /// and will return the OID which isn't what we want.
+    /// The efficient and transaction-safe strategy is to
+    /// move the sequence forward first, and make the insert
+    /// with an explicit id.
+        if ( $CFG->dbfamily === 'postgres' && $returnid == true ) {
+            if ($nextval = (int)get_field_sql("SELECT NEXTVAL('{$CFG->prefix}{$table}_{$primarykey}_seq')")) {
+                $dataobject->{$primarykey} = $nextval;
+            }
+        }
+
+    /// Begin DIRTY HACK
+        if ($CFG->dbfamily == 'oracle') {
+            oracle_dirty_hack($table, $dataobject); // Convert object to the correct "empty" values for Oracle DB
+        }
+    /// End DIRTY HACK
+
+    /// Under Oracle, MSSQL and PostgreSQL we have our own insert record process
+    /// detect all the clob/blob fields and change their contents to @#CLOB#@ and @#BLOB#@
+    /// saving them into $foundclobs and $foundblobs [$fieldname]->contents
+    /// Same for mssql (only processing blobs - image fields)
+        if ($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') {
+            $foundclobs = array();
+            $foundblobs = array();
+            db_detect_lobs($table, $dataobject, $foundclobs, $foundblobs);
+        }
+
+    /// Under Oracle, if the primary key inserted has been requested OR
+    /// if there are LOBs to insert, we calculate the next value via
+    /// explicit query to the sequence.
+    /// Else, the pre-insert trigger will do the job, because the primary
+    /// key isn't needed at all by the rest of PHP code
+        if ($CFG->dbfamily === 'oracle' && ($returnid == true || !empty($foundclobs) || !empty($foundblobs))) {
+        /// We need this here (move this function to dmlib?)
+            include_once($CFG->libdir . '/ddllib.php');
+            $xmldb_table = new XMLDBTable($table);
+            $seqname = find_sequence_name($xmldb_table);
+            if (!$seqname) {
+            /// Fallback, seqname not found, something is wrong. Inform and use the alternative getNameForObject() method
+                debugging('Sequence name for table ' . $table->getName() . ' not found', DEBUG_DEVELOPER);
+                $generator = new XMLDBoci8po();
+                $generator->setPrefix($CFG->prefix);
+                $seqname = $generator->getNameForObject($table, $primarykey, 'seq');
+            }
+            if ($nextval = (int)$db->GenID($seqname)) {
+                $dataobject->{$primarykey} = $nextval;
+            } else {
+                debugging('Not able to get value from sequence ' . $seqname, DEBUG_DEVELOPER);
+            }
+        }
+
+    /// Get the correct SQL from adoDB
+        if (!$insertSQL = $db->GetInsertSQL($rs, (array)$dataobject, true)) {
+            return false;
+        }
+
+    /// Under Oracle, MSSQL and PostgreSQL, replace all the '@#CLOB#@' and '@#BLOB#@' ocurrences to proper default values
+    /// if we know we have some of them in the query
+        if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') &&
+          (!empty($foundclobs) || !empty($foundblobs))) {
+        /// Initial configuration, based on DB
+            switch ($CFG->dbfamily) {
+                case 'oracle':
+                    $clobdefault = 'empty_clob()'; //Value of empty default clobs for this DB
+                    $blobdefault = 'empty_blob()'; //Value of empty default blobs for this DB
+                    break;
+                case 'mssql':
+                case 'postgres':
+                    $clobdefault = 'null'; //Value of empty default clobs for this DB (under mssql this won't be executed
+                    $blobdefault = 'null'; //Value of empty default blobs for this DB
+                    break;
+            }
+            $insertSQL = str_replace("'@#CLOB#@'", $clobdefault, $insertSQL);
+            $insertSQL = str_replace("'@#BLOB#@'", $blobdefault, $insertSQL);
+        }
+
+    /// Run the SQL statement
+        if (!$rs = $db->Execute($insertSQL)) {
+            debugging($db->ErrorMsg() .'<br /><br />'.s($insertSQL));
+            if (!empty($CFG->dblogerror)) {
+                $debug=array_shift(debug_backtrace());
+                error_log("SQL ".$db->ErrorMsg()." in {$debug['file']} on line {$debug['line']}. STATEMENT:  $insertSQL");
+            }
+            return false;
+        }
+
+    /// Under Oracle and PostgreSQL, finally, update all the Clobs and Blobs present in the record
+    /// if we know we have some of them in the query
+        if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'postgres') &&
+          !empty($dataobject->{$primarykey}) &&
+          (!empty($foundclobs) || !empty($foundblobs))) {
+            if (!db_update_lobs($table, $dataobject->{$primarykey}, $foundclobs, $foundblobs)) {
+                return false; //Some error happened while updating LOBs
+            }
+        }
+
+    /// If a return ID is not needed then just return true now (but not in MSSQL DBs, where we may have some pending tasks)
+        if (!$returnid && $CFG->dbfamily != 'mssql') {
+            return true;
+        }
+
+    /// We already know the record PK if it's been passed explicitly,
+    /// or if we've retrieved it from a sequence (Postgres and Oracle).
+        if (!empty($dataobject->{$primarykey})) {
+            return $dataobject->{$primarykey};
+        }
+
+    /// This only gets triggered with MySQL and MSQL databases
+    /// however we have some postgres fallback in case we failed
+    /// to find the sequence.
+        $id = $db->Insert_ID();
+
+    /// Under MSSQL all the Clobs and Blobs (IMAGE) present in the record
+    /// if we know we have some of them in the query
+        if (($CFG->dbfamily == 'mssql') &&
+          !empty($id) &&
+          (!empty($foundclobs) || !empty($foundblobs))) {
+            if (!db_update_lobs($table, $id, $foundclobs, $foundblobs)) {
+                return false; //Some error happened while updating LOBs
+            }
+        }
+
+        if ($CFG->dbfamily === 'postgres') {
+            // try to get the primary key based on id
+            if ( ($rs = $db->Execute('SELECT '. $primarykey .' FROM '. $CFG->prefix . $table .' WHERE oid = '. $id))
+                 && ($rs->RecordCount() == 1) ) {
+                trigger_error("Retrieved $primarykey from oid on table $table because we could not find the sequence.");
+                return (integer)reset($rs->fields);
+            }
+            trigger_error('Failed to retrieve primary key after insert: SELECT '. $primarykey .
+                          ' FROM '. $CFG->prefix . $table .' WHERE oid = '. $id);
+            return false;
+        }
+
+        return (integer)$id;
+
+    }
+}
+
+
+/**
+ * This function is used to convert all the Oracle 1-space defaults to the empty string
+ * like a really DIRTY HACK to allow it to work better until all those NOT NULL DEFAULT ''
+ * fields will be out from Moodle.
+ * @param string the string to be converted to '' (empty string) if it's ' ' (one space)
+ * @param mixed the key of the array in case we are using this function from array_walk,
+ *              defaults to null for other (direct) uses
+ * @return boolean always true (the converted variable is returned by reference)
+ */
+function onespace2empty(&$item, $key=null) {
+    $item = $item == ' ' ? '' : $item;
+    return true;
+}
Index: lib/ddl/mysql_sql_generator.php
===================================================================
RCS file: lib/ddl/mysql_sql_generator.php
diff -N lib/ddl/mysql_sql_generator.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/ddl/mysql_sql_generator.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,384 @@
+<?php // $Id: mysql.class.php,v 1.38 2007/10/10 05:25:24 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once($CFG->libdir.'/ddl/sql_generator.php');
+
+/// This class generate SQL code to be used against MySQL
+/// It extends XMLDBgenerator so everything can be
+/// overriden as needed to generate correct SQL.
+
+class mysql_sql_generator extends sql_generator {
+
+/// Only set values that are different from the defaults present in XMLDBgenerator
+
+    public $quote_string = '`';   // String used to quote names
+
+    public $default_for_char = '';      // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
+
+    public $drop_default_value_required = true; //To specify if the generator must use some DEFAULT clause to drop defaults
+    public $drop_default_value = NULL; //The DEFAULT clause required to drop defaults
+
+    public $primary_key_name = ''; //To force primary key names to one string (null=no force)
+
+    public $drop_primary_key = 'ALTER TABLE TABLENAME DROP PRIMARY KEY'; // Template to drop PKs
+                // with automatic replace for TABLENAME and KEYNAME
+
+    public $drop_unique_key = 'ALTER TABLE TABLENAME DROP KEY KEYNAME'; // Template to drop UKs
+                // with automatic replace for TABLENAME and KEYNAME
+
+    public $drop_foreign_key = 'ALTER TABLE TABLENAME DROP FOREIGN KEY KEYNAME'; // Template to drop FKs
+                // with automatic replace for TABLENAME and KEYNAME
+
+    public $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
+    public $sequence_name = 'auto_increment'; //Particular name for inline sequences in this generator
+
+    public $enum_extra_code = false; //Does the generator need to add extra code to generate code for the enums in the table
+
+    public $add_after_clause = true; // Does the generator need to add the after clause for fields
+
+    public $concat_character = null; //Characters to be used as concatenation operator. If not defined
+                                  //MySQL CONCAT function will be use
+
+    public $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY COLUMN COLUMNSPECS'; //The SQL template to alter columns
+
+    public $drop_index_sql = 'ALTER TABLE TABLENAME DROP INDEX INDEXNAME'; //SQL sentence to drop one index
+                                                               //TABLENAME, INDEXNAME are dinamically replaced
+
+    public $rename_index_sql = null; //SQL sentence to rename one index (MySQL doesn't support this!)
+                                      //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dinamically replaced
+
+    public $rename_key_sql = null; //SQL sentence to rename one key (MySQL doesn't support this!)
+                                      //TABLENAME, OLDKEYNAME, NEWKEYNAME are dinamically replaced
+
+    /**
+     * Creates one new XMLDBmysql
+     */
+    public function __construct($mdb) {
+        parent::__construct($mdb);
+    }
+
+    /**
+     * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
+     */
+    public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
+
+        switch ($xmldb_type) {
+            case XMLDB_TYPE_INTEGER:    // From http://mysql.com/doc/refman/5.0/en/numeric-types.html!
+                if (empty($xmldb_length)) {
+                    $xmldb_length = 10;
+                }
+                if ($xmldb_length > 9) {
+                    $dbtype = 'BIGINT';
+                } else if ($xmldb_length > 6) {
+                    $dbtype = 'INT';
+                } else if ($xmldb_length > 4) {
+                    $dbtype = 'MEDIUMINT';
+                } else if ($xmldb_length > 2) {
+                    $dbtype = 'SMALLINT';
+                } else {
+                    $dbtype = 'TINYINT';
+                }
+                $dbtype .= '(' . $xmldb_length . ')';
+                break;
+            case XMLDB_TYPE_NUMBER:
+                $dbtype = $this->number_type;
+                if (!empty($xmldb_length)) {
+                    $dbtype .= '(' . $xmldb_length;
+                    if (!empty($xmldb_decimals)) {
+                        $dbtype .= ',' . $xmldb_decimals;
+                    }
+                    $dbtype .= ')';
+                }
+                break;
+            case XMLDB_TYPE_FLOAT:
+                $dbtype = 'DOUBLE';
+                if (!empty($xmldb_decimals)) {
+                    if ($xmldb_decimals < 6) {
+                        $dbtype = 'FLOAT';
+                    }
+                }
+                if (!empty($xmldb_length)) {
+                    $dbtype .= '(' . $xmldb_length;
+                    if (!empty($xmldb_decimals)) {
+                        $dbtype .= ',' . $xmldb_decimals;
+                    }
+                    $dbtype .= ')';
+                }
+                break;
+            case XMLDB_TYPE_CHAR:
+                $dbtype = 'VARCHAR';
+                if (empty($xmldb_length)) {
+                    $xmldb_length='255';
+                }
+                $dbtype .= '(' . $xmldb_length . ')';
+                break;
+            case XMLDB_TYPE_TEXT:
+                if (empty($xmldb_length)) {
+                    $xmldb_length = 'small';
+                }
+                if ($xmldb_length == 'small') {
+                    $dbtype = 'TEXT';
+                } else if ($xmldb_length == 'medium') {
+                    $dbtype = 'MEDIUMTEXT';
+                } else {
+                    $dbtype = 'LONGTEXT';
+                }
+                break;
+            case XMLDB_TYPE_BINARY:
+                if (empty($xmldb_length)) {
+                    $xmldb_length = 'small';
+                }
+                if ($xmldb_length == 'small') {
+                    $dbtype = 'BLOB';
+                } else if ($xmldb_length == 'medium') {
+                    $dbtype = 'MEDIUMBLOB';
+                } else {
+                    $dbtype = 'LONGBLOB';
+                }
+                break;
+            case XMLDB_TYPE_DATETIME:
+                $dbtype = 'DATETIME';
+        }
+        return $dbtype;
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public function getCreateEnumSQL($xmldb_table, $xmldb_field) {
+    /// For MySQL, just alter the field
+        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum
+     * (usually invoked from getModifyEnumSQL()
+     */
+    public function getDropEnumSQL($xmldb_table, $xmldb_field) {
+    /// For MySQL, just alter the field
+        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
+    /// Just a wrapper over the getAlterFieldSQL() function for MySQL that
+    /// is capable of handling defaults
+        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
+    }
+
+    /**
+     * Given one correct XMLDBField and the new name, returns the SQL statements
+     * to rename it (inside one array)
+     * MySQL is pretty diferent from the standard to justify this oveloading
+     */
+    public function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
+
+    /// Need a clone of xmldb_field to perform the change leaving original unmodified
+        $xmldb_field_clone = clone($xmldb_field);
+
+    /// Change the name of the field to perform the change
+        $xmldb_field_clone->setName($xmldb_field_clone->getName() . ' ' . $newname);
+
+        $fieldsql = $this->getFieldSQL($xmldb_field_clone);
+
+        $sql = 'ALTER TABLE ' . $this->getTableName($xmldb_table) . ' CHANGE ' . $fieldsql;
+
+        return array($sql);
+    }
+
+    /**
+     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default
+     * (usually invoked from getModifyDefaultSQL()
+     */
+    public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
+    /// Just a wrapper over the getAlterFieldSQL() function for MySQL that
+    /// is capable of handling defaults
+        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
+    }
+
+    /**
+     * Given one XMLDB Field, return its enum SQL
+     */
+    public function getEnumSQL($xmldb_field) {
+        return 'enum(' . implode(', ', $xmldb_field->getEnumValues()) . ')';
+    }
+
+    /**
+     * Returns the code (in array) needed to add one comment to the table
+     */
+    function getCommentSQL ($xmldb_table) {
+        $comment = '';
+
+        if ($xmldb_table->getComment()) {
+            $comment .= 'ALTER TABLE ' . $this->getTableName($xmldb_table);
+            $comment .= " COMMENT='" . $this->addslashes(substr($xmldb_table->getComment(), 0, 60)) . "'";
+        }
+        return array($comment);
+    }
+
+    /**
+     * Given one XMLDBTable returns one array with all the check constrainsts
+     * in the table (fetched from DB)
+     * Optionally the function allows one xmldb_field to be specified in
+     * order to return only the check constraints belonging to one field.
+     * Each element contains the name of the constraint and its description
+     * If no check constraints are found, returns an empty array
+     * MySQL doesn't have check constraints in this implementation, but
+     * we return them based on the enum fields in the table
+     */
+    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
+
+        global $db;
+
+        $tablename = $xmldb_table->getName($xmldb_table);
+
+        $this->mdb->reset_columns($tablename);
+
+    /// Fetch all the columns in the table
+        if (!$columns = $this->mdb->get_columns($tablename)) {
+            return array();
+        }
+
+    /// Filter by the required field if specified
+        if ($xmldb_field) {
+            $filter = $xmldb_field->getName();
+            if (!isset($columns[$filter])) {
+                return array();
+            }
+            $column = ($columns[$filter]);
+            if (!empty($column->enums)) {
+                $result = new object;
+                $result->name = $filter;
+                $result->description = implode(', ', $column->enums);
+                return array($result);
+            } else {
+                return array();
+            }
+
+        } else {
+            $results = array();
+        /// Iterate over columns searching for enums
+            foreach ($columns as $key => $column) {
+            /// Enum found, let's add it to the constraints list
+                if (!empty($column->enums)) {
+                    $result = new object;
+                    $result->name = $key;
+                    $result->description = implode(', ', $column->enums);
+                    $results[$key] = $result;
+                }
+            }
+            return $results;
+        }
+    }
+
+    /**
+     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
+     * return if such name is currently in use (true) or no (false)
+     * (invoked from getNameForObject()
+     */
+    public function isNameInUse($object_name, $type, $table_name) {
+
+    /// Calculate the real table name
+        $xmldb_table = new XMLDBTable($table_name);
+        $tname = $this->getTableName($xmldb_table);
+
+        switch($type) {
+            case 'ix':
+            case 'uix':
+            /// First of all, check table exists
+                $metatables = $this->mdb->get_tables();
+                if (isset($metatables[$tname])) {
+                /// Fetch all the indexes in the table
+                    if ($indexes = $this->mdb->get_indexes($tname)) {
+                    /// Look for existing index in array
+                        if (isset($indexes[$object_name])) {
+                            return true;
+                        }
+                    }
+                }
+                break;
+        }
+        return false; //No name in use found
+    }
+
+
+    /**
+     * Returns an array of reserved words (lowercase) for this DB
+     */
+    public static function getReservedWords() {
+    /// This file contains the reserved words for MySQL databases
+    /// from http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html
+        $reserved_words = array (
+            'add', 'all', 'alter', 'analyze', 'and', 'as', 'asc',
+            'asensitive', 'before', 'between', 'bigint', 'binary',
+            'blob', 'both', 'by', 'call', 'cascade', 'case', 'change',
+            'char', 'character', 'check', 'collate', 'column',
+            'condition', 'connection', 'constraint', 'continue',
+            'convert', 'create', 'cross', 'current_date', 'current_time',
+            'current_timestamp', 'current_user', 'cursor', 'database',
+            'databases', 'day_hour', 'day_microsecond',
+            'day_minute', 'day_second', 'dec', 'decimal', 'declare',
+            'default', 'delayed', 'delete', 'desc', 'describe',
+            'deterministic', 'distinct', 'distinctrow', 'div', 'double',
+            'drop', 'dual', 'each', 'else', 'elseif', 'enclosed', 'escaped',
+            'exists', 'exit', 'explain', 'false', 'fetch', 'float', 'float4',
+            'float8', 'for', 'force', 'foreign', 'from', 'fulltext', 'grant',
+            'group', 'having', 'high_priority', 'hour_microsecond',
+            'hour_minute', 'hour_second', 'if', 'ignore', 'in', 'index',
+            'infile', 'inner', 'inout', 'insensitive', 'insert', 'int', 'int1',
+            'int2', 'int3', 'int4', 'int8', 'integer', 'interval', 'into', 'is',
+            'iterate', 'join', 'key', 'keys', 'kill', 'leading', 'leave', 'left',
+            'like', 'limit', 'lines', 'load', 'localtime', 'localtimestamp',
+            'lock', 'long', 'longblob', 'longtext', 'loop', 'low_priority',
+            'match', 'mediumblob', 'mediumint', 'mediumtext',
+            'middleint', 'minute_microsecond', 'minute_second',
+            'mod', 'modifies', 'natural', 'not', 'no_write_to_binlog',
+            'null', 'numeric', 'on', 'optimize', 'option', 'optionally',
+            'or', 'order', 'out', 'outer', 'outfile', 'precision', 'primary',
+            'procedure', 'purge', 'raid0', 'read', 'reads', 'real',
+            'references', 'regexp', 'release', 'rename', 'repeat', 'replace',
+            'require', 'restrict', 'return', 'revoke', 'right', 'rlike', 'schema',
+            'schemas', 'second_microsecond', 'select', 'sensitive',
+            'separator', 'set', 'show', 'smallint', 'soname', 'spatial',
+            'specific', 'sql', 'sqlexception', 'sqlstate', 'sqlwarning',
+            'sql_big_result', 'sql_calc_found_rows', 'sql_small_result',
+            'ssl', 'starting', 'straight_join', 'table', 'terminated', 'then',
+            'tinyblob', 'tinyint', 'tinytext', 'to', 'trailing', 'trigger', 'true',
+            'undo', 'union', 'unique', 'unlock', 'unsigned', 'update',
+            'upgrade', 'usage', 'use', 'using', 'utc_date', 'utc_time',
+            'utc_timestamp', 'values', 'varbinary', 'varchar', 'varcharacter',
+            'varying', 'when', 'where', 'while', 'with', 'write', 'x509',
+            'xor', 'year_month', 'zerofill'
+        );
+        return $reserved_words;
+    }
+}
+
+?>
Index: lib/dml/odbc_mssql_adodb_moodle_database.php
===================================================================
RCS file: lib/dml/odbc_mssql_adodb_moodle_database.php
diff -N lib/dml/odbc_mssql_adodb_moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/odbc_mssql_adodb_moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,45 @@
+<?php  //$Id:$
+
+require_once($CFG->libdir.'/dml/moodle_database.php');
+require_once($CFG->libdir.'/dml/adodb_moodle_database.php');
+require_once($CFG->libdir.'/dml/mssql_adodb_moodle_database.php');
+
+/**
+ * Experimenta mssql odbc database class using adodb backend
+ * @package dmlib
+ */
+class odbc_mssql_adodb_moodle_database extends mssql_adodb_moodle_database {
+    function __construct ($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        parent::__construct($dbhost, $dbuser, $dbpass, $dbname, false, $prefix);
+    }
+
+    /**
+     * Returns database type
+     * @return string db type mysql, mysqli, postgres7
+     */
+    protected function get_dbtype() {
+        return 'odbc_mssql';
+    }
+
+    protected function configure_dbconnection() {
+        if (!defined('ADODB_ASSOC_CASE')) {
+            define ('ADODB_ASSOC_CASE', 0);
+        }
+        $this->db->SetFetchMode(ADODB_ASSOC_CASE);
+
+        /// No need to set charset. It must be specified in the driver conf
+        /// Allow quoted identifiers
+            $this->db->Execute('SET QUOTED_IDENTIFIER ON');
+        /// Force ANSI nulls so the NULL check was done by IS NULL and NOT IS NULL
+        /// instead of equal(=) and distinct(<>) simbols
+            $this->db->Execute('SET ANSI_NULLS ON');
+        /// Enable sybase quotes, so addslashes and stripslashes will use "'"
+            ini_set('magic_quotes_sybase', '1');
+        /// NOTE: Not 100% useful because GPC has been addslashed with the setting off
+        ///       so IT'S MANDATORY TO CHANGE THIS UNDER php.ini or .htaccess for this DB
+        ///       or to turn off magic_quotes to allow Moodle to do it properly
+
+        return true;
+    }
+
+}
Index: lib/xmldb/XMLDBFile.class.php
===================================================================
RCS file: lib/xmldb/XMLDBFile.class.php
diff -N lib/xmldb/XMLDBFile.class.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/xmldb/XMLDBFile.class.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,201 @@
+<?php // $Id: XMLDBFile.class.php,v 1.6 2007/10/10 05:25:14 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represents an entire XMLDB file
+
+class XMLDBFile extends XMLDBObject {
+
+    var $path;
+    var $schema;
+    var $dtd;
+    var $xmldb_structure;
+
+    /**
+     * Constructor of the XMLDBFile
+     */
+    function XMLDBFile ($path) {
+        parent::XMLDBObject($path);
+        $this->path = $path;
+        $this->xmldb_structure = NULL;
+    }
+
+    /**
+     * Determine if the XML file exists
+     */
+    function fileExists() {
+        if (file_exists($this->path) && is_readable($this->path)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Determine if the XML is writeable
+     */
+    function fileWriteable() {
+        if (is_writeable(dirname($this->path))) {
+            return true;
+        }
+        return false;
+    }
+
+    function &getStructure() {
+        return $this->xmldb_structure;
+    }
+
+    /**
+     * This function will check/validate the XML file for correctness 
+     * Dinamically if will use the best available checker/validator
+     * (expat syntax checker or DOM schema validator
+     */
+    function validateXMLStructure() {
+
+    /// Going to perform complete DOM schema validation
+        if (extension_loaded('dom')) {
+        /// Let's capture errors
+        if (function_exists('libxml_use_internal_errors')) {
+            libxml_use_internal_errors(true); // This function is PHP5 only (MDL-8730)
+        }
+
+        /// Create and load XML file
+            $parser = new DOMDocument();
+            $parser->load($this->path);
+        /// Only validate if we have a schema
+            if (!empty($this->schema) && file_exists($this->schema)) {
+                $parser->schemaValidate($this->schema);
+            }
+        /// Check for errors
+            $errors = false;
+            if (function_exists('libxml_get_errors')) {
+                $errors = libxml_get_errors();
+            }
+
+        /// Prepare errors
+            if (!empty($errors)) {
+            /// Create one structure to store errors
+                $structure = new XMLDBStructure($this->path);
+            /// Add errors to structure
+                $structure->errormsg = 'XML Error: ';
+                foreach ($errors as $error) {
+                    $structure->errormsg .= sprintf("%s at line %d. ", 
+                                                     trim($error->message, "\n\r\t ."),
+                                                     $error->line);
+                }
+            /// Add structure to file
+                $this->xmldb_structure = $structure;
+            /// Check has failed
+                return false;
+            }
+        }
+    /// Going to perform expat simple check (no validation)
+        else if (function_exists('xml_parser_create')) {
+            $parser = xml_parser_create();
+            if (!xml_parse($parser, file_get_contents($this->path))) {
+            /// Create one structure to store errors
+                $structure = new XMLDBStructure($this->path);
+            /// Add error to structure
+                $structure->errormsg = sprintf("XML Error: %s at line %d", 
+                         xml_error_string(xml_get_error_code($parser)),
+                         xml_get_current_line_number($parser));
+            /// Add structure to file
+                $this->xmldb_structure = $structure;
+            /// Check has failed
+                return false;
+            }
+        /// Free parser resources
+            xml_parser_free($parser);
+        }
+    /// Arriving here, something is really wrong because nor dom not expat are present
+        else {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Load and the XMLDB structure from file
+     */
+    function loadXMLStructure() {
+        if ($this->fileExists()) {
+        /// Let's validate the XML file
+            if (!$this->validateXMLStructure()) {
+                return false;
+            }
+        /// File exists, so let's process it
+        /// Load everything to a big array
+            $xmlarr = xmlize(file_get_contents($this->path));
+        /// Convert array to xmldb structure
+            $this->xmldb_structure = $this->arr2XMLDBStructure($xmlarr);
+        /// Analize results
+            if ($this->xmldb_structure->isLoaded()) {
+                $this->loaded = true;
+                return true;
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * This function takes an xmlized array and put it into one XMLDBStructure
+     */
+    function arr2XMLDBStructure ($xmlarr) {
+        $structure = new XMLDBStructure($this->path);
+        $structure->arr2XMLDBStructure($xmlarr);
+        return $structure;
+    }
+
+    /**
+     * This function sets the DTD of the XML file
+     */
+    function setDTD($path) {
+        $this->dtd = $path;
+    }
+
+    /**
+     * This function sets the schema of the XML file
+     */
+    function setSchema($path) {
+        $this->schema = $path;
+    }
+
+    /**
+     * This function saves the whole XMLDBStructure to its file
+     */
+    function saveXMLFile() {
+
+        $result = true;
+
+        $structure =& $this->getStructure();
+
+        $result = file_put_contents($this->path, $structure->xmlOutput());
+
+        return $result;
+    }
+}
+
+?>
Index: lib/dml/moodle_database.php
===================================================================
RCS file: lib/dml/moodle_database.php
diff -N lib/dml/moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1241 @@
+<?php  //$Id: $
+
+/**
+ * Abstract class representing moodle database interface.
+ * @package dmlib
+ */
+abstract class moodle_database {
+
+    /**
+     * supports :name, "?" or both types of parameters?
+     * must be set in implementing class constructor
+     */
+    protected $param_types;
+
+    protected $database_manager;
+
+    // db connection options
+    protected $dbhost;
+    protected $dbuser;
+    protected $dbpass;
+    protected $dbname;
+    protected $dbpersist;
+    protected $prefix;
+
+    // TODO: perf stuff goes here
+    // TODO: do we really need record caching??
+
+    /**
+     * Contructor - sets up database connection, prints error in case of problem.
+     * @param string $dbhost
+     * @param string $dbuser
+     * @param string $dbpass
+     * @param string $dbname
+     * @param string $dbpersist
+     * @param string $prefix table prefix
+     */
+    public function __construct($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        $this->dbhost    = $dbhost;
+        $this->dbuser    = $dbuser;
+        $this->dbpass    = $dbpass;
+        $this->dbname    = $dbname;
+        $this->dbpersist = $dbpersist;
+        $this->prefix    = $prefix;
+    }
+
+    /**
+     * Returns database family type - describes SQL dialect
+     * @return string db family name (mysql, postgres, mssql, oracle, etc.)
+     */
+    public abstract function get_dbfamily();
+
+    /**
+     * Returns database server info array
+     * @return array
+     */
+    public abstract function get_server_info();
+
+    /**
+     * Returns database table prefix
+     * @return string database table prefix
+     */
+    public function get_prefix() {
+        return $this->prefix;
+    }
+
+    /**
+     * Returns database type
+     * @return string db type mysql, mysqli, postgres7
+     */
+    protected abstract function get_dbtype();
+
+    /**
+     * Returns supported query parameter types
+     * @return bitmask
+     */
+    protected abstract function allowed_param_types();
+
+    /**
+     * Connect to db specified in constructor
+     * Must be called before any other methods.
+     * @return bool success
+     */
+    public abstract function connect();
+
+    /**
+     * Returns last error reported by database engine.
+     */
+    public abstract function get_last_error();
+
+    /**
+     * Report database error somewhere
+     * TODO: do we need some message with hints?
+     * @param string $sql query which caused problems
+     * @param array $params optional query parameters
+     * @param mixed $obj optional library specific object
+     */
+    protected function report_error($sql, array $params=null, $obj=null) {
+        debugging($this->get_last_error() .'<br /><br />'. s($sql).'<br /> ['.var_export($params, true).']');
+    }
+
+    /**
+     * Constructs IN() or = sql fragment
+     * @param mixed $items single or array of values
+     * @param int $type bound param type
+     * @param string named param placeholder start
+     * @return array - $sql and $params
+     */
+    public function get_in_or_equal($items, $type=SQL_PARAMS_QM, $start='param0000') {
+        if ($type == SQL_PARAMS_QM) {
+            if (!is_array($items) or count($items) == 1) {
+                $sql = '= ?';
+                $params = array($items);
+            } else {
+                $sql = 'IN ('.implode(',', array_fill(0, count($items), '?')).')';
+                $params = array_values($items);
+            }
+
+        } else if ($type == SQL_PARAMS_NAMED) {
+            if (!is_array($items) or count($items) == 1) {
+                $sql = '= :'.$start;
+                $params = array($start=>$items);
+            } else {
+                $params = array();
+                $sql = array();
+                foreach ($items as $item) {
+                    $params[$start] = $item;
+                    $sql .= ':'.$start++;
+                }
+                $sql = 'IN ('.implode(',', $sql).')';
+            }
+
+        } else {
+            error('todo: type not implemented');
+        }
+        return array($sql, $params);
+    }
+
+    /**
+     * Normalizes sql query parameters and verifies parameters.
+     * @param string $sql query or part of it
+     * @param array $params query parameters
+     */
+    public function fix_sql_params($sql, array $params=null) {
+        $params = (array)$params; // mke null array if needed
+        $allowed_types = $this->allowed_param_types();
+
+        // convert table names
+        $sql = preg_replace('/\{([a-z][a-z0-9_]*)\}/', $this->prefix.'$1', $sql);
+
+        $named_count = preg_match_all('/(?!:):[a-z][a-z0-9_]*/', $sql, $named_matches); // :: used in pgsql casts
+        $dolar_count = preg_match_all('/\$[1-9][0-9]*/', $sql, $dolar_matches);
+        $q_count     = substr_count($sql, '?');
+
+        $count = 0;
+
+        if ($named_count) {
+            $type = SQL_PARAMS_NAMED;
+            $count = $named_count;
+
+        }
+        if ($dolar_count) {
+            if ($count) {
+                error('ERROR: Mixed types of sql query parameters!!');
+            }
+            $type = SQL_PARAMS_DOLAR;
+            $count = $dolar_count;
+
+        }
+        if ($q_count) {
+            if ($count) {
+                error('ERROR: Mixed types of sql query parameters!!');
+            }
+            $type = SQL_PARAMS_QM;
+            $count = $q_count;
+
+        }
+
+        if (!$count) {
+             // ignore params
+            if ($allowed_types & SQL_PARAMS_NAMED) {
+                return array($sql, array(), SQL_PARAMS_NAMED);
+            } else if ($allowed_types & SQL_PARAMS_QM) {
+                return array($sql, array(), SQL_PARAMS_QM);
+            } else {
+                return array($sql, array(), SQL_PARAMS_DOLAR);
+            }
+        }
+
+        if ($count > count($params)) {
+            error('ERROR: Incorrect number of query parameters!! '.s($sql));
+        }
+
+        if ($type & $allowed_types) { // bitwise AND
+            if ($count == count($params)) {
+                if ($type == SQL_PARAMS_QM) {
+                    return array($sql, array_values($params), SQL_PARAMS_QM); // 0-based array required
+                } else {
+                    //better do the validation of names bellow
+                }
+            }
+            // needs some fixing or validation - there might be more params than needed
+            $target_type = $type;
+
+        } else {
+            $target_type = $allowed_types;
+        }
+
+        if ($type == SQL_PARAMS_NAMED) {
+            $finalparams = array();
+            foreach ($named_matches[0] as $key) {
+                $key = trim($key, ':');
+                if (!array_key_exists($key, $params)) {
+                    error('ERROR: missing param "'.$key.'" in query');
+                }
+                $finalparams[$key] = $params[$key];
+            }
+            if ($count != count($finalparams)) {
+                error('ERROR: duplicate parameter name in query');
+            }
+
+            if ($target_type & SQL_PARAMS_QM) {
+                $sql = preg_replace('/(?!:):[a-z][a-z0-9_]*/', '?', $sql);
+                return array($sql, array_values($finalparams), SQL_PARAMS_QM); // 0-based required
+            } else if ($target_type & SQL_PARAMS_NAMED) {
+                return array($sql, $finalparams, SQL_PARAMS_NAMED);
+            } else {  // $type & SQL_PARAMS_DOLAR
+                error('Pg $1, $2 bound syntax not supported yet :-(');
+            }
+
+        } else if ($type == SQL_PARAMS_DOLAR) {
+            error('Pg $1, $2 bound syntax not supported yet :-(');
+
+        } else { // $type == SQL_PARAMS_QM
+            if (count($params) != $count) {
+                $params = array_slice($params, 0, $count);
+            }
+
+            if ($target_type & SQL_PARAMS_QM) {
+                return array($sql, array_values($params), SQL_PARAMS_QM); // 0-based required
+            } else if ($target_type & SQL_PARAMS_NAMED) {
+                $finalparams = array();
+                $pname = 'param00000';
+                $parts = explode('?', $sql);
+                $sql = array_shift($parts);
+                foreach ($parts as $part) {
+                    $param = array_shift($params);
+                    $pname++;
+                    $sql .= ':'.$pname.$part;
+                    $finalparams[$pname] = $param;
+                }
+                return array($sql, $finalparams, SQL_PARAMS_NAMED);
+            } else {  // $type & SQL_PARAMS_DOLAR
+                error('Pg $1, $2 bound syntax not supported yet :-(');
+            }
+        }
+    }
+
+    /**
+     * Return tables in database with current prefix
+     * @return array of table names
+     */
+    public abstract function get_tables();
+
+    /**
+     * Return table indexes
+     * @return array of arrays
+     */
+    public abstract function get_indexes($table);
+
+    /**
+     * Returns datailed information about columns in table. This information is cached internally.
+     * @param string $table name
+     * @return array array of database_column_info objects indexed with column names
+     */
+    public abstract function get_columns($table);
+
+    /**
+     * Reset internal column details cache
+     * @param string $table - empty means all, or one if name of table given
+     * @return void
+     */
+    public abstract function reset_columns($table=null);
+
+    /**
+     * Returns sql generator used for db manipulation.
+     * Used mostly in upgrade.php scripts.
+     * @return object database_manager instance
+     */
+    public function get_manager() {
+        global $CFG;
+
+        if (!$this->database_manager) {
+            require_once($CFG->libdir.'/ddllib.php');
+            require_once($CFG->libdir.'/ddl/database_manager.php');
+
+            $classname = $this->get_dbfamily().'_sql_generator';
+            require_once("$CFG->libdir/ddl/$classname.php");
+            $generator = new $classname($this);
+
+            $this->database_manager = new database_manager($this, $generator);
+        }
+        return $this->database_manager;
+    }
+
+    /**
+     * Attempt to change db encoding toUTF-8 if poossible
+     * @return bool success
+     */
+    public function change_db_encoding() {
+        return false;
+    }
+
+    /**
+     * Is db in unicode mode?
+     * @return bool
+     */
+    public function setup_is_unicodedb() {
+        return true;
+    }
+
+    /**
+     * Enable/disable very detailed debugging
+     * TODO: do we need levels?
+     * @param bool $state
+     */
+    public abstract function set_debug($state);
+
+    /**
+     * Returns debug status
+     * @return bool $state
+     */
+    public abstract function get_debug();
+
+    /**
+     * Enable/disable detailed sql logging
+     * TODO: do we need levels?
+     * @param bool $state
+     */
+    public abstract function set_logging($state);
+
+    /**
+     * Do NOT use in code, to be used by database_manager only!
+     * @param string $sql query
+     * @return bool success
+     */
+    public abstract function change_database_structure($sql);
+
+    /**
+     * Execute general sql query. Should be used only when no other method suitable.
+     * Do NOT use this to make changes in db structure, use database_manager::execute_sql() instead!
+     * @param string $sql query
+     * @param array $params query parameters
+     * @return bool success
+     */
+    public abstract function execute($sql, array $params=null);
+
+    /**
+     * Get a number of records as a moodle_recordset.
+     *
+     * Selects records from the table $table.
+     *
+     * If specified, only records meeting $conditions.
+     *
+     * If specified, the results will be sorted as specified by $sort. This
+     * is added to the SQL as "ORDER BY $sort". Example values of $sort
+     * mightbe "time ASC" or "time DESC".
+     *
+     * If $fields is specified, only those fields are returned.
+     *
+     * Since this method is a little less readable, use of it should be restricted to
+     * code where it's possible there might be large datasets being returned.  For known
+     * small datasets use get_records - it leads to simpler code.
+     *
+     * If you only want some of the records, specify $limitfrom and $limitnum.
+     * The query will skip the first $limitfrom records (according to the sort
+     * order) and then return the next $limitnum records. If either of $limitfrom
+     * or $limitnum is specified, both must be present.
+     *
+     * The return value is a moodle_recordset
+     * if the query succeeds. If an error occurrs, false is returned.
+     *
+     * @param string $table the table to query.
+     * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
+     * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+     * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an moodle_recorset object, or false if an error occured.
+     */
+    public function get_recordset($table, array $conditions=null, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
+        list($select, $params) = $this->where_clause($conditions);
+        return $this->get_recordset_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
+    }
+
+    /**
+     * Get a number of records a moodle_recordset.
+     *
+     * Only records where $field takes one of the values $values are returned.
+     * $values should be a comma-separated list of values, for example "4,5,6,10"
+     * or "'foo','bar','baz'".
+     *
+     * Other arguments and the return type as for @see function get_recordset.
+     *
+     * @param string $table the table to query.
+     * @param string $field a field to check (optional).
+     * @param array $values array of values the field must have
+     * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+     * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an moodle_recorset object, or false if an error occured.
+     */
+    public function get_recordset_list($table, $field, array $values, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
+        $params = array();
+        $select = array();
+        foreach ($values as $value) {
+            if (is_bool($value)) {
+                $value = (int)$value;
+            }
+            if (is_null($value)) {
+                $select[] = "$field IS NULL";
+            } else {
+                $select[] = "$field = ?";
+                $params[] = $value;
+            }
+        }
+        $select = implode(" AND ", $select);
+        return get_recordset_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
+    }
+
+    /**
+     * Get a number of records a moodle_recordset.
+     *
+     * If given, $select is used as the SELECT parameter in the SQL query,
+     * otherwise all records from the table are returned.
+     *
+     * Other arguments and the return type as for @see function get_recordset.
+     *
+     * @param string $table the table to query.
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+     * @param string $fields a comma separated list of fields to return (optional, by default all fields are returned).
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an moodle_recorset object, or false if an error occured.
+     */
+    public function get_recordset_select($table, $select, array $params=null, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
+        if ($select) {
+            $select = "WHERE $select";
+        }
+        if ($sort) {
+            $sort = " ORDER BY $sort";
+        }
+        return $this->get_recordset_sql("SELECT * FROM {$this->prefix}$table $select $sort", $params, $limitfrom, $limitnum);
+    }
+
+    /**
+     * Get a number of records as an moodle_recordset.  $sql must be a complete SQL query.
+     * Since this method is a little less readable, use of it should be restricted to
+     * code where it's possible there might be large datasets being returned.  For known
+     * small datasets use get_records_sql - it leads to simpler code.
+     *
+     * The return type is as for @see function get_recordset.
+     *
+     * @param string $sql the SQL select query to execute.
+     * @param array $params array of sql parameters
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an moodle_recorset object, or false if an error occured.
+     */
+    public abstract function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0);
+
+    /**
+     * Get a number of records as an array of objects.
+     *
+     * If the query succeeds and returns at least one record, the
+     * return value is an array of objects, one object for each
+     * record found. The array key is the value from the first
+     * column of the result set. The object associated with that key
+     * has a member variable for each column of the results.
+     *
+     * @param string $table the table to query.
+     * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
+     * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+     * @param string $fields a comma separated list of fields to return (optional, by default
+     *   all fields are returned). The first field will be used as key for the
+     *   array so must be a unique field such as 'id'.
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an array of objects, or empty array if no records were found, or false if an error occured.
+     */
+    public function get_records($table, array $conditions=null, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
+        list($select, $params) = $this->where_clause($conditions);
+        return $this->get_records_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
+    }
+
+    /**
+     * Get a number of records as an array of objects.
+     *
+     * Return value as for @see function get_records.
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $field The field to search
+     * @param string $values array of values
+     * @param string $sort Sort order (as valid SQL sort parameter)
+     * @param string $fields A comma separated list of fields to be returned from the chosen table. If specified,
+     *   the first field should be a unique one such as 'id' since it will be used as a key in the associative
+     *   array.
+     * @return mixed an array of objects, or empty array if no records were found, or false if an error occured.
+     */
+    public function get_records_list($table, $field, array $values=null, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
+        $params = array();
+        $select = array();
+        $values = (array)$values;
+        foreach ($values as $value) {
+            if (is_bool($value)) {
+                $value = (int)$value;
+            }
+            if (is_null($value)) {
+                $select[] = "$field IS NULL";
+            } else {
+                $select[] = "$field = ?";
+                $params[] = $value;
+            }
+        }
+        $select = implode(" AND ", $select);
+        return $this->get_records_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
+    }
+
+    /**
+     * Get a number of records as an array of objects.
+     *
+     * Return value as for @see function get_records.
+     *
+     * @param string $table the table to query.
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+     * @param string $fields a comma separated list of fields to return
+     *   (optional, by default all fields are returned). The first field will be used as key for the
+     *   array so must be a unique field such as 'id'.
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an array of objects, or empty array if no records were found, or false if an error occured.
+     */
+    public function get_records_select($table, $select, array $params=null, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
+        if ($select) {
+            $select = "WHERE $select";
+        }
+        if ($sort) {
+            $sort = " ORDER BY $sort";
+        }
+        return $this->get_records_sql("SELECT $fields FROM {$this->prefix}$table $select $sort", $params, $limitfrom, $limitnum);
+    }
+
+    /**
+     * Get a number of records as an array of objects.
+     *
+     * Return value as for @see function get_records.
+     *
+     * @param string $sql the SQL select query to execute. The first column of this SELECT statement
+     *   must be a unique value (usually the 'id' field), as it will be used as the key of the
+     *   returned array.
+     * @param array $params array of sql parameters
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an array of objects, or empty array if no records were found, or false if an error occured.
+     */
+    public abstract function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnum=0);
+
+    /**
+     * Get the first two columns from a number of records as an associative array.
+     *
+     * Arguments as for @see function get_recordset.
+     *
+     * If no errors occur the return value
+     * is an associative whose keys come from the first field of each record,
+     * and whose values are the corresponding second fields.
+     * False is returned if an error occurs.
+     *
+     * @param string $table the table to query.
+     * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
+     * @param string $sort an order to sort the results in (optional, a valid SQL ORDER BY parameter).
+     * @param string $fields a comma separated list of fields to return - the number of fields should be 2!
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an associative array, or false if an error occured.
+     */
+    public function get_records_menu($table, array $conditions=null, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
+        $menu = array();
+        if ($records = $this->get_records($table, $conditions, $sort, $fields, $limitfrom, $limitnum)) {
+            foreach ($records as $record) {
+                $record = (array)$record;
+                $key   = array_shift($record);
+                $value = array_shift($record);
+                $menu[$key] = $value;
+            }
+        }
+        return $menu;
+    }
+
+    /**
+     * Get the first two columns from a number of records as an associative array.
+     *
+     * Arguments as for @see function get_recordset_select.
+     * Return value as for @see function get_records_menu.
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @param string $sort Sort order (optional) - a valid SQL order parameter
+     * @param string $fields A comma separated list of fields to be returned from the chosen table - the number of fields should be 2!
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an associative array, or false if an error occured.
+     */
+    public function get_records_select_menu($table, $select, array $params=null, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
+        $menu = array();
+        if ($records = $this->get_records_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum)) {
+            foreach ($records as $record) {
+                $key   = array_unshift($record);
+                $value = array_unshift($record);
+                $menu[$key] = $value;
+            }
+        }
+        return $menu;
+    }
+
+    /**
+     * Get the first two columns from a number of records as an associative array.
+     *
+     * Arguments as for @see function get_recordset_sql.
+     * Return value as for @see function get_records_menu.
+     *
+     * @param string $sql The SQL string you wish to be executed.
+     * @param array $params array of sql parameters
+     * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
+     * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
+     * @return mixed an associative array, or false if an error occured.
+     */
+    public function get_records_sql_menu($sql, array $params=null, $limitfrom=0, $limitnum=0) {
+        $menu = array();
+        if ($records = $this->get_records_sql($sql, $params, $limitfrom, $limitnum)) {
+            foreach ($records as $record) {
+                $key   = array_unshift($record);
+                $value = array_unshift($record);
+                $menu[$key] = $value;
+            }
+        }
+        return $menu;
+    }
+
+    /**
+     * Get a single database record as an object
+     *
+     * @param string $table The table to select from.
+     * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
+     * @param string $fields A comma separated list of fields to be returned from the chosen table.
+     * @param bool $ignoremultiple ignore multiple records if found
+     * @return mixed a fieldset object containing the first mathcing record, or false if none found.
+     */
+    public function get_record($table, array $conditions, $fields='*', $ignoremultiple=false) {
+        list($select, $params) = $this->where_clause($conditions);
+        return $this->get_record_select($table, $select, $params, $fields, $ignoremultiple);
+    }
+
+    /**
+     * Get a single database record as an object
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @param string $fields A comma separated list of fields to be returned from the chosen table.
+     * @param bool $ignoremultiple ignore multiple records if found
+     * @return mixed a fieldset object containing the first mathcing record, or false if none found.
+     */
+    public function get_record_select($table, $select, array $params=null, $fields='*', $ignoremultiple=false) {
+        if ($select) {
+            $select = "WHERE $select";
+        }
+        return $this->get_record_sql("SELECT $fields FROM {$this->prefix}$table $select", $params, $ignoremultiple);
+    }
+
+    /**
+     * Get a single record as an object using an SQL statement
+     *
+     * The SQL statement should normally only return one record. In debug mode
+     * you will get a warning if more records are found. In non-debug mode,
+     * it just returns the first record.
+     *
+     * Use get_records_sql() if more matches possible!
+     *
+     * @param string $sql The SQL string you wish to be executed, should normally only return one record.
+     * @param array $params array of sql parameters
+     * @param bool $ignoremultiple ignore multiple records if found
+     * @return mixed a fieldset object containing the first mathcing record, or false if none found.
+     */
+    public function get_record_sql($sql, array $params=null, $ignoremultiple=false) {
+        $count = $ignoremultiple ? 1 : 2;
+        if (!$mrs = $this->get_recordset_sql($sql, $params, 0, $count)) {
+            return false;
+        }
+        if (!$mrs->valid()) {
+            $mrs->close();
+            return false;
+        }
+
+        $return = (object)$mrs->current();
+
+        $mrs->next();
+        if (!$ignoremultiple and $mrs->valid()) {
+            debugging('Error: mdb->get_record() found more than one record!');
+        }
+
+        $mrs->close();
+        return $return;
+    }
+
+    /**
+     * Get a single value from a table row where all the given fields match the given values.
+     *
+     * @param string $table the table to query.
+     * @param string $return the field to return the value of.
+     * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
+     * @return mixed the specified value, or false if an error occured.
+     */
+    public function get_field($table, $return, array $conditions) {
+        list($select, $params) = $this->where_clause($conditions);
+        return $this->get_field_select($table, $return, $select, $params);
+    }
+
+    /**
+     * Get a single value from a table row.
+     *
+     * @param string $table the table to query.
+     * @param string $return the field to return the value of.
+     * @param string $select A fragment of SQL to be used in a where clause returning one row with one column
+     * @param array $params array of sql parameters
+     * @return mixed the specified value, or false if an error occured.
+     */
+    public function get_field_select($table, $return, $select, array $params=null) {
+        if ($select) {
+            $select = "WHERE $select";
+        }
+        return $this->get_field_sql("SELECT $return FROM {$this->prefix}$table $select", $params);
+    }
+
+    /**
+     * Get a single value from a table.
+     *
+     * @param string $table the table to query.
+     * @param string $return the field to return the value of.
+     * @param string $sql The SQL query returning one row with one column
+     * @param array $params array of sql parameters
+     * @return mixed the specified value, or false if an error occured.
+     */
+    public function get_field_sql($sql, array $params=null) {
+        if ($mrs = $this->get_recordset_sql($sql, $params, 0, 1)) {
+            if ($mrs->valid()) {
+                $record = $mrs->current();
+                return reset($record); // first column
+            }
+            $mrs->close();
+        }
+        return false;
+    }
+
+    /**
+     * Selects rows and return values of chosen field as array.
+     *
+     * @param string $table the table to query.
+     * @param string $return the field we are intered in
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @return mixed array of values or false if an error occured
+     */
+    public function get_fieldset_select($table, $return, $select, array $params=null) {
+        if ($select) {
+            $select = "WHERE $select";
+        }
+        return $this->get_fieldset_sql("SELECT $return FROM {$this->prefix}$table $select", $params);
+    }
+
+    /**
+     * Selects rows and return values of first column as array.
+     *
+     * @param string $sql The SQL query
+     * @param array $params array of sql parameters
+     * @return mixed array of values or false if an error occured
+     */
+    public abstract function get_fieldset_sql($sql, array $params=null);
+
+    /**
+     * Insert new record into database, as fast as possible, no safety checks, lobs not supported.
+     * @param string $table name
+     * @param mixed $params data record as object or array
+     * @param bool $returnit return it of inserted record
+     * @param bool $bulk true means repeated inserts expected
+     * @return mixed success or new id
+     */
+    public abstract function insert_record_raw($table, $params, $returnid=true, $bulk=false);
+
+    /**
+     * Insert a record into a table and return the "id" field if required,
+     * Some conversions and safety checks are carried out. Lobs are supported.
+     * If the return ID isn't required, then this just reports success as true/false.
+     * $data is an object containing needed data
+     * @param string $table The database table to be inserted into
+     * @param object $data A data object with values for one or more fields in the record
+     * @param bool $returnid Should the id of the newly created record entry be returned? If this option is not requested then true/false is returned.
+     * @return mixed success or new ID
+     */
+    public abstract function insert_record($table, $dataobject, $returnid=true, $bulk=false);
+
+    /**
+     * Update record in database, as fast as possible, no safety checks, lobs not supported.
+     * @param string $table name
+     * @param mixed $params data record as object or array
+     * @param bool true means repeated updates expected
+     * @return bool success
+     */
+    public abstract function update_record_raw($table, $params, $bulk=false);
+
+    /**
+     * Update a record in a table
+     *
+     * $dataobject is an object containing needed data
+     * Relies on $dataobject having a variable "id" to
+     * specify the record to update
+     *
+     * @param string $table The database table to be checked against.
+     * @param object $dataobject An object with contents equal to fieldname=>fieldvalue. Must have an entry for 'id' to map to the table specified.
+     * @param bool true means repeated updates expected
+     * @return bool success
+     */
+    public abstract function update_record($table, $dataobject, $bulk=false);
+
+
+    /**
+     * Set a single field in every table row where all the given conditions met.
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $newfield the field to set.
+     * @param string $newvalue the value to set the field to.
+     * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
+     * @return bool success
+     */
+    public function set_field($table, $newfield, $newvalue, array $conditions=null) {
+        list($select, $params) = $this->where_clause($conditions);
+        return $this->set_field_select($table, $newfield, $newvalue, $select, $params);
+    }
+
+    /**
+     * Set a single field in every table row where the select statement evaluates to true.
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $newfield the field to set.
+     * @param string $newvalue the value to set the field to.
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @return bool success
+     */
+    public abstract function set_field_select($table, $newfield, $newvalue, $select, array $params=null);
+
+
+    /**
+     * Count the records in a table where all the given conditions met.
+     *
+     * @param string $table The table to query.
+     * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
+     * @return int The count of records returned from the specified criteria.
+     */
+    public function count_records($table, array $conditions=null, array $params=null) {
+        list($select, $params) = $this->where_clause($conditions);
+        return $this->count_records_select($table, $select, $params);
+    }
+
+    /**
+     * Count the records in a table which match a particular WHERE clause.
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $select A fragment of SQL to be used in a WHERE clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @param string $countitem The count string to be used in the SQL call. Default is COUNT('x').
+     * @return int The count of records returned from the specified criteria.
+     */
+    public function count_records_select($table, $select, array $params=null, $countitem="COUNT('x')") {
+        if ($select) {
+            $select = "WHERE $select";
+        }
+        return $this->count_records_sql("SELECT $countitem FROM {$this->prefix}$table $select", $params);
+    }
+
+    /**
+     * Get the result of a SQL SELECT COUNT(...) query.
+     *
+     * Given a query that counts rows, return that count. (In fact,
+     * given any query, return the first field of the first record
+     * returned. However, this method should only be used for the
+     * intended purpose.) If an error occurrs, 0 is returned.
+     *
+     * @param string $sql The SQL string you wish to be executed.
+     * @param array $params array of sql parameters
+     * @return int the count. If an error occurrs, 0 is returned.
+     */
+    public function count_records_sql($sql, array $params=null) {
+        if ($count = $this->get_field_sql($sql, $params)) {
+            return $count;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Test whether a record exists in a table where all the given conditions met.
+     *
+     * The record to test is specified by giving up to three fields that must
+     * equal the corresponding values.
+     *
+     * @param string $table The table to check.
+     * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
+     * @return bool true if a matching record exists, else false.
+     */
+    public function record_exists($table, array $conditions) {
+        list($select, $params) = $this->where_clause($conditions);
+        return $this->record_exists_select($table, $select, $params);
+    }
+
+    /**
+     * Test whether any records exists in a table which match a particular WHERE clause.
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $select A fragment of SQL to be used in a WHERE clause in the SQL call.
+     * @param array $params array of sql parameters
+     * @return bool true if a matching record exists, else false.
+     */
+    public function record_exists_select($table, $select, array $params=null) {
+        if ($select) {
+            $select = "WHERE $select";
+        }
+        return $this->record_exists_sql("SELECT 'x' FROM {$this->prefix}$table $select", $params);
+    }
+
+    /**
+     * Test whether a SQL SELECT statement returns any records.
+     *
+     * This function returns true if the SQL statement executes
+     * without any errors and returns at least one record.
+     *
+     * @param string $sql The SQL statement to execute.
+     * @param array $params array of sql parameters
+     * @return bool true if the SQL executes without errors and returns at least one record.
+     */
+    public function record_exists_sql($sql, array $params=null) {
+        if ($mrs = $this->get_recordset_sql($sql, $params, 0, 1)) {
+            $return = $mrs->valid();
+            $mrs->close();
+            return $return;
+        }
+        return false;
+    }
+
+    /**
+     * Delete the records from a table where all the given conditions met.
+     *
+     * @param string $table the table to delete from.
+     * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
+     * @return returns success.
+     */
+    public function delete_records($table, array $conditions) {
+        list($select, $params) = $this->where_clause($conditions);
+        return $this->delete_records_select($table, $select, $params);
+    }
+
+    /**
+     * Delete one or more records from a table
+     *
+     * @param string $table The database table to be checked against.
+     * @param string $select A fragment of SQL to be used in a where clause in the SQL call (used to define the selection criteria).
+     * @param array $params array of sql parameters
+     * @return returns success.
+     */
+    public abstract function delete_records_select($table, $select, array $params=null);
+
+
+
+/// sql contructs
+    /**
+     * Returns the SQL text to be used in order to perform one bitwise AND operation
+     * between 2 integers.
+     * @param integer int1 first integer in the operation
+     * @param integer int2 second integer in the operation
+     * @return string the piece of SQL code to be used in your statement.
+     */
+    public function sql_bitand($int1, $int2) {
+        return '((' . $int1 . ') & (' . $int2 . '))';
+    }
+
+    /**
+     * Returns the SQL text to be used in order to perform one bitwise NOT operation
+     * with 1 integer.
+     * @param integer int1 integer in the operation
+     * @return string the piece of SQL code to be used in your statement.
+     */
+    public function sql_bitnot($int1) {
+        return '(~(' . $int1 . '))';
+    }
+
+    /**
+     * Returns the SQL text to be used in order to perform one bitwise OR operation
+     * between 2 integers.
+     * @param integer int1 first integer in the operation
+     * @param integer int2 second integer in the operation
+     * @return string the piece of SQL code to be used in your statement.
+     */
+    public function sql_bitor($int1, $int2) {
+        return '((' . $int1 . ') | (' . $int2 . '))';
+    }
+
+    /**
+     * Returns the SQL text to be used in order to perform one bitwise XOR operation
+     * between 2 integers.
+     * @param integer int1 first integer in the operation
+     * @param integer int2 second integer in the operation
+     * @return string the piece of SQL code to be used in your statement.
+     */
+    public function sql_bitxor($int1, $int2) {
+        return '((' . $int1 . ') ^ (' . $int2 . '))';
+    }
+
+    /**
+     * Returns the SQL to be used in order to CAST one CHAR column to INTEGER.
+     *
+     * Be aware that the CHAR column you're trying to cast contains really
+     * int values or the RDBMS will throw an error!
+     *
+     * @param string fieldname the name of the field to be casted
+     * @param boolean text to specify if the original column is one TEXT (CLOB) column (true). Defaults to false.
+     * @return string the piece of SQL code to be used in your statement.
+     */
+    public function sql_cast_char2int($fieldname, $text=false) {
+        return ' ' . $fieldname . ' ';
+    }
+
+    /**
+     * Returns the SQL text to be used to compare one TEXT (clob) column with
+     * one varchar column, because some RDBMS doesn't support such direct
+     * comparisons.
+     * @param string fieldname the name of the TEXT field we need to order by
+     * @param string number of chars to use for the ordering (defaults to 32)
+     * @return string the piece of SQL code to be used in your statement.
+     */
+    public function sql_compare_text($fieldname, $numchars=32) {
+        return $this->sql_order_by_text($fieldname, $numchars);
+    }
+
+    /**
+     * Returns the proper SQL to do CONCAT between the elements passed
+     * Can take many parameters - just a passthrough to $db->Concat()
+     *
+     * @param string $element
+     * @return string
+     */
+    public abstract function sql_concat();
+
+    /**
+     * Returns the proper SQL to do CONCAT between the elements passed
+     * with a given separator
+     *
+     * @uses $db
+     * @param string $separator
+     * @param array  $elements
+     * @return string
+     */
+    public abstract function sql_concat_join($separator="' '", $elements=array());
+
+    /**
+     * Returns the proper SQL (for the dbms in use) to concatenate $firstname and $lastname
+     *
+     * @param string $firstname User's first name
+     * @param string $lastname User's last name
+     * @return string
+     */
+    function sql_fullname($first='firstname', $last='lastname') {
+        return $this->sql_concat($first, "' '", $last);
+    }
+
+    /**
+     * Returns the proper SQL to do LIKE in a case-insensitive way
+     *
+     * Note the LIKE are case sensitive for Oracle. Oracle 10g is required to use
+     * the caseinsensitive search using regexp_like() or NLS_COMP=LINGUISTIC :-(
+     * See http://docs.moodle.org/en/XMLDB_Problems#Case-insensitive_searches
+     *
+     * @return string
+     */
+    public function sql_ilike() {
+        return 'LIKE';
+    }
+
+    /**
+     * Returns the SQL text to be used to order by one TEXT (clob) column, because
+     * some RDBMS doesn't support direct ordering of such fields.
+     * Note that the use or queries being ordered by TEXT columns must be minimised,
+     * because it's really slooooooow.
+     * @param string fieldname the name of the TEXT field we need to order by
+     * @param string number of chars to use for the ordering (defaults to 32)
+     * @return string the piece of SQL code to be used in your statement.
+     */
+    public function sql_order_by_text($fieldname, $numchars=32) {
+        return $fieldname;
+    }
+
+    /**
+     * Returns the proper substr() function for each DB
+     * Relies on ADOdb $db->substr property
+     */
+    public abstract function sql_substr();
+
+    public function where_clause(array $conditions=null) {
+        $allowed_types = $this->allowed_param_types();
+        if (empty($conditions)) {
+            return array('', array());
+        }
+        $where = array();
+        $params = array();
+        foreach ($conditions as $key=>$value) {
+            if (is_null($value)) {
+                $where[] = "$key IS NULL";
+            } else {
+                if ($allowed_types & SQL_PARAMS_NAMED) {
+                    $where[] = "$key = :$key";
+                    $params[$key] = $value;
+                } else {
+                    $where[] = "$key = ?";
+                    $params[] = $value;
+                }
+            }
+        }
+        $where = implode(" AND ", $where);
+        return array($where, $params);
+    }
+
+    /**
+     * Returns the empty string char used by every supported DB. To be used when
+     * we are searching for that values in our queries. Only Oracle uses this
+     * for now (will be out, once we migrate to proper NULLs if that days arrives)
+     */
+    function sql_empty() {
+        return '';
+    }
+
+    /**
+     * Returns the proper SQL to know if one field is empty.
+     *
+     * Note that the function behavior strongly relies on the
+     * parameters passed describing the field so, please,  be accurate
+     * when speciffying them.
+     *
+     * Also, note that this function is not suitable to look for
+     * fields having NULL contents at all. It's all for empty values!
+     *
+     * This function should be applied in all the places where conditins of
+     * the type:
+     *
+     *     ... AND fieldname = '';
+     *
+     * are being used. Final result should be:
+     *
+     *     ... AND ' . sql_isempty('tablename', 'fieldname', true/false, true/false);
+     *
+     * (see parameters description below)
+     *
+     * @param string $tablename name of the table (without prefix). Not used for now but can be
+     *                          necessary in the future if we want to use some introspection using
+     *                          meta information against the DB. /// TODO ///
+     * @param string $fieldname name of the field we are going to check
+     * @param boolean $nullablefield to specify if the field us nullable (true) or no (false) in the DB
+     * @param boolean $textfield to specify if it is a text (also called clob) field (true) or a varchar one (false)
+     * @return string the sql code to be added to check for empty values
+     */
+    public function sql_isempty($tablename, $fieldname, $nullablefield, $textfield) {
+        return " $fieldname = '' ";
+    }
+
+    /**
+     * Returns the proper SQL to know if one field is not empty.
+     *
+     * Note that the function behavior strongly relies on the
+     * parameters passed describing the field so, please,  be accurate
+     * when speciffying them.
+     *
+     * This function should be applied in all the places where conditions of
+     * the type:
+     *
+     *     ... AND fieldname != '';
+     *
+     * are being used. Final result should be:
+     *
+     *     ... AND ' . sql_isnotempty('tablename', 'fieldname', true/false, true/false);
+     *
+     * (see parameters description below)
+     *
+     * @param string $tablename name of the table (without prefix). Not used for now but can be
+     *                          necessary in the future if we want to use some introspection using
+     *                          meta information against the DB. /// TODO ///
+     * @param string $fieldname name of the field we are going to check
+     * @param boolean $nullablefield to specify if the field us nullable (true) or no (false) in the DB
+     * @param boolean $textfield to specify if it is a text (also called clob) field (true) or a varchar one (false)
+     * @return string the sql code to be added to check for non empty values
+     */
+    public function sql_isnotempty($tablename, $fieldname, $nullablefield, $textfield) {
+        return ' ( NOT ' . $this->sql_isempty($tablename, $fieldname, $nullablefield, $textfield) . ') ';
+    }
+
+/// transactions
+    /**
+     * on DBs that support it, switch to transaction mode and begin a transaction
+     * you'll need to ensure you call commit_sql() or your changes *will* be lost.
+     *
+     * this is _very_ useful for massive updates
+     */
+    public function begin_sql() {
+        return true;
+    }
+
+    /**
+     * on DBs that support it, commit the transaction
+     */
+    public function commit_sql() {
+        return true;
+    }
+
+    /**
+     * on DBs that support it, rollback the transaction
+     */
+    public function rollback_sql() {
+        return true;
+    }
+}
Index: lib/xmldb/XMLDBIndex.class.php
===================================================================
RCS file: lib/xmldb/XMLDBIndex.class.php
diff -N lib/xmldb/XMLDBIndex.class.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/xmldb/XMLDBIndex.class.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,264 @@
+<?php // $Id: XMLDBIndex.class.php,v 1.9 2007/10/10 05:25:14 nicolasconnault Exp $
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.com  //
+//           (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com  //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represent one XMLDB Index
+
+class XMLDBIndex extends XMLDBObject {
+
+    var $unique;
+    var $fields;
+
+    /**
+     * Creates one new XMLDBIndex
+     */
+    function XMLDBIndex($name) {
+        parent::XMLDBObject($name);
+        $this->unique = false;
+        $this->fields = array();
+    }
+
+    /**
+     * Set all the attributes of one XMLDBIndex
+     *
+     * @param string type XMLDB_INDEX_UNIQUE, XMLDB_INDEX_NOTUNIQUE
+     * @param array fields an array of fieldnames to build the index over
+     */
+    function setAttributes($type, $fields) {
+        $this->unique = !empty($type) ? true : false;
+        $this->fields = $fields;
+    }
+
+    /**
+     * Get the index unique
+     */
+    function getUnique() {
+        return $this->unique;
+    }
+
+    /**
+     * Set the index unique
+     */
+    function setUnique($unique = true) {
+        $this->unique = $unique;
+    }
+
+    /**
+     * Set the index fields
+     */
+    function setFields($fields) {
+        $this->fields = $fields;
+    }
+
+    /**
+     * Get the index fields
+     */
+    function &getFields() {
+        return $this->fields;
+    }
+
+    /**
+     * Load data from XML to the index
+     */
+    function arr2XMLDBIndex($xmlarr) {
+
+        $result = true;
+
+    /// Debug the table
+    /// traverse_xmlize($xmlarr);                   //Debug
+    /// print_object ($GLOBALS['traverse_array']);  //Debug
+    /// $GLOBALS['traverse_array']="";              //Debug
+
+    /// Process key attributes (name, unique, fields, comment, previous, next)
+        if (isset($xmlarr['@']['NAME'])) {
+            $this->name = trim($xmlarr['@']['NAME']);
+        } else {
+            $this->errormsg = 'Missing NAME attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+
+        if (isset($xmlarr['@']['UNIQUE'])) {
+            $unique = strtolower(trim($xmlarr['@']['UNIQUE']));
+            if ($unique == 'true') {
+                $this->unique = true;
+            } else if ($unique == 'false') {
+                $this->unique = false;
+            } else {
+                $this->errormsg = 'Incorrect UNIQUE attribute (true/false allowed)';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        } else {
+                $this->errormsg = 'Undefined UNIQUE attribute';
+                $this->debug($this->errormsg);
+                $result = false;
+        }
+
+        if (isset($xmlarr['@']['FIELDS'])) {
+            $fields = strtolower(trim($xmlarr['@']['FIELDS']));
+            if ($fields) {
+                $fieldsarr = explode(',',$fields);
+                if ($fieldsarr) {
+                    foreach ($fieldsarr as $key => $element) {
+                        $fieldsarr [$key] = trim($element);
+                    }
+                } else {
+                    $this->errormsg = 'Incorrect FIELDS attribute (comma separated of fields)';
+                    $this->debug($this->errormsg);
+                    $result = false;
+                }
+            } else {
+                $this->errormsg = 'Empty FIELDS attribute';
+                $this->debug($this->errormsg);
+                $result = false;
+            }
+        } else {
+            $this->errormsg = 'Missing FIELDS attribute';
+            $this->debug($this->errormsg);
+            $result = false;
+        }
+    /// Finally, set the array of fields
+        $this->fields = $fieldsarr;
+
+        if (isset($xmlarr['@']['COMMENT'])) {
+            $this->comment = trim($xmlarr['@']['COMMENT']);
+        }
+
+        if (isset($xmlarr['@']['PREVIOUS'])) {
+            $this->previous = trim($xmlarr['@']['PREVIOUS']);
+        }
+
+        if (isset($xmlarr['@']['NEXT'])) {
+            $this->next = trim($xmlarr['@']['NEXT']);
+        }
+
+    /// Set some attributes
+        if ($result) {
+            $this->loaded = true;
+        }
+        $this->calculateHash();
+        return $result;
+    }
+
+    /**
+     * This function calculate and set the hash of one XMLDBIndex
+     */
+     function calculateHash($recursive = false) {
+        if (!$this->loaded) {
+            $this->hash = NULL;
+        } else {
+            $key = $this->unique . implode (', ', $this->fields);
+            $this->hash = md5($key);
+        }
+    }
+
+    /**
+     *This function will output the XML text for one index
+     */
+    function xmlOutput() {
+        $o = '';
+        $o.= '        <INDEX NAME="' . $this->name . '"';
+        if ($this->unique) {
+            $unique = 'true';
+        } else {
+            $unique = 'false';
+        }
+        $o.= ' UNIQUE="' . $unique . '"';
+        $o.= ' FIELDS="' . implode(', ', $this->fields) . '"';
+        if ($this->comment) {
+            $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"';
+        }
+        if ($this->previous) {
+            $o.= ' PREVIOUS="' . $this->previous . '"';
+        }
+        if ($this->next) {
+            $o.= ' NEXT="' . $this->next . '"';
+        }
+        $o.= '/>' . "\n";
+
+        return $o;
+    }
+
+    /**
+     * This function will set all the attributes of the XMLDBIndex object
+     * based on information passed in one ADOindex
+     */
+    function setFromADOIndex($adoindex) {
+
+    /// Set the unique field
+        $this->unique = false;
+    /// Set the fields, converting all them to lowercase
+        $fields = array_flip(array_change_key_case(array_flip($adoindex['columns'])));
+        $this->fields = $fields;
+    /// Some more fields
+        $this->loaded = true;
+        $this->changed = true;
+    }
+
+    /**
+     * Returns the PHP code needed to define one XMLDBIndex
+     */
+    function getPHP() {
+
+        $result = '';
+
+    /// The type
+        $unique = $this->getUnique();
+        if (!empty($unique)) {
+            $result .= 'XMLDB_INDEX_UNIQUE, ';
+        } else {
+            $result .= 'XMLDB_INDEX_NOTUNIQUE, ';
+        }
+    /// The fields
+        $indexfields = $this->getFields();
+        if (!empty($indexfields)) {
+            $result .= 'array(' . "'".  implode("', '", $indexfields) . "')";
+        } else {
+            $result .= 'null';
+        }
+    /// Return result
+        return $result;
+    }
+
+    /**
+     * Shows info in a readable format
+     */
+    function readableInfo() {
+        $o = '';
+    /// unique
+        if ($this->unique) {
+            $o .= 'unique';
+        } else {
+            $o .= 'not unique';
+        }
+    /// fields
+        $o .= ' (' . implode(', ', $this->fields) . ')';
+
+        return $o;
+    }
+}
+
+?>
Index: lib/dml/mssql_n_adodb_moodle_database.php
===================================================================
RCS file: lib/dml/mssql_n_adodb_moodle_database.php
diff -N lib/dml/mssql_n_adodb_moodle_database.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/dml/mssql_n_adodb_moodle_database.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,45 @@
+<?php  //$Id:$
+
+require_once($CFG->libdir.'/dml/moodle_database.php');
+require_once($CFG->libdir.'/dml/adodb_moodle_database.php');
+require_once($CFG->libdir.'/dml/mssql_adodb_moodle_database.php');
+
+/**
+ * MSSQL database class using adodb backend
+ * @package dmlib
+ */
+class mssql_n_adodb_moodle_database extends mssql_adodb_moodle_database {
+    function __construct ($dbhost, $dbuser, $dbpass, $dbname, $dbpersist, $prefix) {
+        parent::__construct($dbhost, $dbuser, $dbpass, $dbname, false, $prefix);
+    }
+
+    /**
+     * Returns database type
+     * @return string db type mysql, mysqli, postgres7
+     */
+    protected function get_dbtype() {
+        return 'mssql_n';
+    }
+
+    protected function configure_dbconnection() {
+        if (!defined('ADODB_ASSOC_CASE')) {
+            define ('ADODB_ASSOC_CASE', 0);
+        }
+        $this->db->SetFetchMode(ADODB_ASSOC_CASE);
+
+        /// No need to set charset. It must be specified in the driver conf
+        /// Allow quoted identifiers
+            $this->db->Execute('SET QUOTED_IDENTIFIER ON');
+        /// Force ANSI nulls so the NULL check was done by IS NULL and NOT IS NULL
+        /// instead of equal(=) and distinct(<>) simbols
+            $this->db->Execute('SET ANSI_NULLS ON');
+        /// Enable sybase quotes, so addslashes and stripslashes will use "'"
+            ini_set('magic_quotes_sybase', '1');
+        /// NOTE: Not 100% useful because GPC has been addslashed with the setting off
+        ///       so IT'S MANDATORY TO CHANGE THIS UNDER php.ini or .htaccess for this DB
+        ///       or to turn off magic_quotes to allow Moodle to do it properly
+
+        return true;
+    }
+
+}
