]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-14679 ok, here is the big patch with new dmllib and ddlib API, some code is alrea...
authorskodak <skodak>
Thu, 15 May 2008 21:40:00 +0000 (21:40 +0000)
committerskodak <skodak>
Thu, 15 May 2008 21:40:00 +0000 (21:40 +0000)
112 files changed:
admin/cliupgrade.php
admin/cron.php
admin/index.php
admin/innodb.php
admin/mnet/access_control.php
admin/multilangupgrade.php
admin/replace.php
admin/roles/manage.php
admin/timezone.php
admin/xmldb/actions/check_bigints/check_bigints.class.php
admin/xmldb/actions/check_defaults/check_defaults.class.php
admin/xmldb/actions/check_indexes/check_indexes.class.php
admin/xmldb/actions/edit_statement/edit_statement.class.php
admin/xmldb/actions/edit_table/edit_table.class.php
admin/xmldb/actions/edit_xml_file/edit_xml_file.class.php
admin/xmldb/actions/load_xml_file/load_xml_file.class.php
admin/xmldb/actions/main_view/main_view.class.php
admin/xmldb/actions/new_statement/new_statement.class.php
admin/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php
admin/xmldb/actions/test/test.class.php
admin/xmldb/actions/view_reserved_words/view_reserved_words.class.php
admin/xmldb/actions/view_structure_sql/view_structure_sql.class.php
admin/xmldb/actions/view_table_php/view_table_php.class.php
admin/xmldb/actions/view_table_sql/view_table_sql.class.php
admin/xmldb/index.php
auth/cas/auth.php
auth/ldap/auth.php
backup/lib.php
blocks/admin/block_admin.php
blog/lib.php
calendar/event.php
course/edit_form.php
course/lib.php
enrol/authorize/db/upgrade.php
file.php
grade/edit/outcome/import.php
group/index.php
group/overview.php
help.php
index.php
lib/accesslib.php
lib/adminlib.php
lib/blocklib.php
lib/datalib.php
lib/db/install.xml
lib/db/upgrade.php
lib/db/upgradelib.php
lib/ddl/database_manager.php [new file with mode: 0644]
lib/ddl/mssql_sql_generator.php [moved from lib/xmldb/classes/generators/mssql/mssql.class.php with 77% similarity]
lib/ddl/mysql_sql_generator.php [moved from lib/xmldb/classes/generators/mysql/mysql.class.php with 76% similarity]
lib/ddl/oracle_sql_generator.php [moved from lib/xmldb/classes/generators/oci8po/oci8po.class.php with 82% similarity]
lib/ddl/postgres_sql_generator.php [moved from lib/xmldb/classes/generators/postgres7/postgres7.class.php with 83% similarity]
lib/ddl/sql_generator.php [moved from lib/xmldb/classes/generators/XMLDBGenerator.class.php with 73% similarity]
lib/ddllib.php
lib/dml/adodb_moodle_database.php [new file with mode: 0644]
lib/dml/adodb_moodle_recordset.php [new file with mode: 0644]
lib/dml/moodle_database.php [new file with mode: 0644]
lib/dml/mssql_adodb_moodle_database.php [new file with mode: 0644]
lib/dml/mssql_n_adodb_moodle_database.php [new file with mode: 0644]
lib/dml/mysql_adodb_moodle_database.php [new file with mode: 0644]
lib/dml/mysqli_adodb_moodle_database.php [new file with mode: 0644]
lib/dml/oci8po_adodb_moodle_database.php [new file with mode: 0644]
lib/dml/oci8po_adodb_moodle_recordset.php [new file with mode: 0644]
lib/dml/odbc_mssql_adodb_moodle_database.php [new file with mode: 0644]
lib/dml/pdo_moodle_database.php [new file with mode: 0644]
lib/dml/pdo_moodle_recordset.php [new file with mode: 0644]
lib/dml/postgres7_adodb_moodle_database.php [new file with mode: 0644]
lib/dmllib.php
lib/dmllib_todo.php [new file with mode: 0644]
lib/environmentlib.php
lib/filelib.php
lib/grade/grade_item.php
lib/grade/lib_wrapper.php
lib/grouplib.php
lib/locallib.php
lib/moodlelib.php
lib/setup.php
lib/setuplib.php
lib/weblib.php
lib/xmldb/XMLDBConstants.php [moved from lib/xmldb/classes/XMLDBConstants.php with 100% similarity]
lib/xmldb/XMLDBField.class.php [moved from lib/xmldb/classes/XMLDBField.class.php with 100% similarity]
lib/xmldb/XMLDBFile.class.php [moved from lib/xmldb/classes/XMLDBFile.class.php with 100% similarity]
lib/xmldb/XMLDBIndex.class.php [moved from lib/xmldb/classes/XMLDBIndex.class.php with 100% similarity]
lib/xmldb/XMLDBKey.class.php [moved from lib/xmldb/classes/XMLDBKey.class.php with 100% similarity]
lib/xmldb/XMLDBObject.class.php [moved from lib/xmldb/classes/XMLDBObject.class.php with 100% similarity]
lib/xmldb/XMLDBStatement.class.php [moved from lib/xmldb/classes/XMLDBStatement.class.php with 89% similarity]
lib/xmldb/XMLDBStructure.class.php [moved from lib/xmldb/classes/XMLDBStructure.class.php with 96% similarity]
lib/xmldb/XMLDBTable.class.php [moved from lib/xmldb/classes/XMLDBTable.class.php with 72% similarity]
lib/xmldb/classes/generators/mssql_n/mssql_n.class.php [deleted file]
lib/xmldb/classes/generators/mysqli/mysqli.class.php [deleted file]
lib/xmldb/classes/generators/odbc_mssql/odbc_mssql.class.php [deleted file]
mod/assignment/db/upgrade.php
mod/chat/lib.php
mod/choice/mod_form.php
mod/data/db/upgrade.php
mod/data/import.php
mod/feedback/db/upgrade.php
mod/forum/db/upgrade.php
mod/glossary/edit.php
mod/glossary/edit_form.php
mod/hotpot/attempt.php
mod/hotpot/db/upgrade.php
mod/hotpot/index.php
mod/hotpot/lib.php
mod/hotpot/restorelib.php
mod/hotpot/view.php
mod/lesson/db/upgrade.php
mod/quiz/report/grading/report.php
mod/quiz/report/overview/report.php
mod/survey/mod_form.php
mod/wiki/ewiki/plugins/page/orphanedpages.php
search/indexlib.php

index e3ddd7f03cb6728a29e1dc1165d291b2f799879a..2b59f6e8ea05633c62d5900dc3e1de8f92f624f2 100644 (file)
@@ -860,16 +860,16 @@ if ( file_exists(dirname(dirname(__FILE__)) . '/config.php')) {
         /// 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 e7f3f01441ca3e811f230e1accfecad08f08757c..9c3449cce3ec7a9aa364b1600007cbf2d4659184 100644 (file)
@@ -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 09f39f5b16642e5710c593d23bb6b63e408fa7ff..bdf0af2ea7617514fb9e9e3350555058ee3e711f 100644 (file)
         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") {
     }
 
 /// 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
                          "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;
             }
         $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);
         }
         set_config('unicodedb', 1);
 
     /// Continue with the instalation
-        $db->debug = false;
+        $DB->set_debug(false);
         if ($status) {
 
             /// Groups install is now in core above.
                 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')) {
                 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()) {
         $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
         $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
         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);
             }
         }
     }
 
 /// 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 e7d82ac2b4462706d2b5b0fbe78a45936cfa22ad..93238106cb1afd6f3f01380e0b87c033b4271caa 100644 (file)
@@ -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()) {
-
-       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 (data_submitted() and $confirm and confirm_sesskey()) {
+
+        notify('Please be patient and wait for this to complete...', 'notifysuccess');
+
+        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 9b3a34cebedfa232562a9f1283096ef03b6843d7..e8ebd9ae6f9e88d6fd42a620a4f7ab0d87bc200d 100644 (file)
@@ -19,7 +19,7 @@ admin_externalpage_setup('ssoaccesscontrol');
 admin_externalpage_print_header();
 
 if (!extension_loaded('openssl')) {
-    print_error('requiresopenssl', 'mnet', '', NULL, true);
+    print_error('requiresopenssl', 'mnet');
 }
 
 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
@@ -27,7 +27,7 @@ $sesskey = sesskey();
 $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]);
 }
@@ -39,13 +39,13 @@ if (!empty($action) and confirm_sesskey()) {
     
     // boot if insufficient permission
     if (!has_capability('moodle/user:delete', $sitecontext)) {
-        error(get_string('nomodifyacl','mnet'));
+        print_error('nomodifyacl','mnet');
     }
 
     // fetch the record in question
     $id = required_param('id', PARAM_INT);
     if (!$idrec = get_record('mnet_sso_access_control', 'id', $id)) {
-        error(get_string('recordnoexists','mnet'), "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
+        print_error('recordnoexists','mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
     }
 
     switch ($action) {
@@ -60,7 +60,7 @@ if (!empty($action) and confirm_sesskey()) {
             // require the access parameter, and it must be 'allow' or 'deny'
             $accessctrl = trim(strtolower(required_param('accessctrl', PARAM_ALPHA)));
             if ($accessctrl != 'allow' and $accessctrl != 'deny') {
-                error(get_string('invalidaccessparam', 'mnet') , "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
+                print_error('invalidaccessparam', 'mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
             }
 
             if (mnet_update_sso_access_control($idrec->username, $idrec->mnet_host_id, $accessctrl)) {
@@ -84,7 +84,7 @@ if ($form = data_submitted() and confirm_sesskey()) {
 
     // check permissions and verify form input
     if (!has_capability('moodle/user:delete', $sitecontext)) {
-        error(get_string('nomodifyacl','mnet'), "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
+        print_error('nomodifyacl','mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
     }
     if (empty($form->username)) {
         $formerror['username'] = get_string('enterausername','mnet');
index 72dff0ae4445826a44f7e7fce44069c9fa11b5b0..0903b652ab06381e77a6a67a7751972ec54f7265 100644 (file)
@@ -24,7 +24,7 @@ if (!$go or !data_submitted() or !confirm_sesskey()) {   /// Print a form
 }
 
 
-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 @@ while(@ob_end_flush());
 
 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 @@ foreach ($tables as $table) {
                             echo '.';
                         }
                         $i++;
-                        $rs->MoveNext();
 
                         if (empty($text) or is_numeric($text)) {
                             continue; // nothing to do
@@ -82,11 +80,10 @@ foreach ($tables as $table) {
                         }
 
                         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 1a6a2a35d1098a3fbfec56a4d117f18a3f125526..cdff6ae39a47a4e9ec9c97f5691dab524438d3fb 100644 (file)
@@ -34,16 +34,16 @@ if (!data_submitted() or !$search or !$replace or !confirm_sesskey()) {   /// Pr
 
 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 1d2b94b9ea7be9aa5d403ecfcea540222f281099..afa4cd9805bbe0a8459b22140b5f33a02cfe6d7b 100755 (executable)
@@ -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);
 
                 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');
                 }
 
 
                 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');
 
                 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');
                     }
 
                     // 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
                             $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) {
                     $role->shortname = $shortname;
                     $role->description = $description;
 
-                    if (!update_record('role', $role)) {
+                    if (!$DB->update_record('role', $role)) {
                         print_error('cannotupdaterole', 'error');
                     }
 
             }
 
             // duplicate current role
-            $sourcerole = get_record('role','id',$roleid);
+            $sourcerole = $DB->get_record('role', array('id'=>$roleid));
 
             $fullname = $sourcerole->name;
             $shortname = $sourcerole->shortname;
                 $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);
 
                 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;
                 $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 94993cc644ecc97b2f09bd07083958838851f370..1c23e9024804a8fda2174a5ea826b5e570d626b3 100644 (file)
@@ -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();
 
 
     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 eb9f8a0e4f1d86ee8a1589b733bf39e60f29e4bb..abaa91cb55abfd1476fe79346585d640b77ec09c 100644 (file)
@@ -76,7 +76,10 @@ class check_bigints extends XMLDBAction {
         $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 @@ class check_bigints extends XMLDBAction {
         $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 @@ class check_bigints extends XMLDBAction {
             $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 @@ class check_bigints extends XMLDBAction {
                     }
                 /// 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 @@ class check_bigints extends XMLDBAction {
                     /// 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 @@ class check_bigints extends XMLDBAction {
                                 /// 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 @@ class check_bigints extends XMLDBAction {
                     $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 0b9fa3fa964ade1775c04c7e8dbcb02638be8648..5b22238f4c34715e0d687cabe984285384930818 100644 (file)
@@ -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 @@ class check_defaults extends XMLDBAction {
         $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 @@ class check_defaults extends XMLDBAction {
                     }
                 /// 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 @@ class check_defaults extends XMLDBAction {
                     }
                 /// 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 @@ class check_defaults extends XMLDBAction {
                     /// 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 @@ class check_defaults extends XMLDBAction {
                             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;
-                                }
 
-                                /// To variable for better handling
-                                $metacolumn = $metacolumns[$xmldb_field->getName()];
+                                    // Get the default value for the field
+                                    $xmldbdefault = $xmldb_field->getDefault();
 
-                                /// Going to check this field in DB
-                                $o.='            <li>' . $this->str['field'] . ': ' . $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;
+                                    }
 
-                                // 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 = '';
-                                }
+                                    /// To variable for better handling
+                                    $metacolumn = $metacolumns[$xmldb_field->getName()];
 
-                                // there *is* a default and it's wrong
-                                if ($physicaldefault != $xmldbdefault) {
-                                    $info = '['.$this->str['shouldbe']." '$xmldbdefault' ".$this->str['butis'].
+                                    /// Going to check this field in DB
+                                    $o.='            <li>' . $this->str['field'] . ': ' . $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 = '';
+                                    }
+
+                                    // 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 @@ class check_defaults extends XMLDBAction {
                     $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 @@ class check_defaults extends XMLDBAction {
                                               $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 e5989e6839c95d975636cb5f141783470e5f73aa..a7596b36712cd50045212633dae47234894c751e 100644 (file)
@@ -74,7 +74,9 @@ class check_indexes extends XMLDBAction {
         $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 @@ class check_indexes extends XMLDBAction {
                     }
                 /// 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 @@ class check_indexes extends XMLDBAction {
                     /// 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 @@ class check_indexes extends XMLDBAction {
                                     }
                                 /// 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 @@ class check_indexes extends XMLDBAction {
                                                 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 @@ class check_indexes extends XMLDBAction {
                                 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 @@ class check_indexes extends XMLDBAction {
                 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 7a9608a39f9695aaef7eefcfa386fa69e38cde82..1e2a5faf79729c18cfc33d1121ecb541ada2793d 100644 (file)
@@ -103,7 +103,7 @@ class edit_statement extends XMLDBAction {
 
     /// 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 8fb90d8a4befd168bcfa20aee77b1ecd54fc115e..d45937b05fbbb4ad5f45da07691bcfde994705aa 100644 (file)
@@ -103,7 +103,7 @@ class edit_table extends XMLDBAction {
 
     /// 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 @@ class edit_table extends XMLDBAction {
         $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 @@ class edit_table extends XMLDBAction {
                     $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 d6036a821d17f13b2de50c596d482dffe5cbaeed..ef2a5bbd27d233eec2f580bf05a47dd111a9e45a 100644 (file)
@@ -72,7 +72,7 @@ class edit_xml_file extends XMLDBAction {
         $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 @@ class edit_xml_file extends XMLDBAction {
             /// 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 @@ class edit_xml_file extends XMLDBAction {
                 $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 @@ class edit_xml_file extends XMLDBAction {
                             $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 64e8a34f42f095d9d3fb025a8f9668be790940e8..9804fd96a551e226b55147c3b7be73d0e5a474b2 100644 (file)
@@ -95,7 +95,7 @@ class load_xml_file extends XMLDBAction {
                 $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 8428343e085ee5bc35acaec34ebfa586c40d4aa1..4f706a5c0a7eb76cca478a0d975de84d81cc912f 100644 (file)
@@ -68,7 +68,7 @@ class main_view extends XMLDBAction {
         $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 @@ class main_view extends XMLDBAction {
     /// 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 f80e9bc4533e5ec074e7f46f02a86bbdfd819f26..c661cf0ceac8a485a7ac44c0a362f0fe0732b2c1 100644 (file)
@@ -60,7 +60,7 @@ class new_statement extends XMLDBAction {
         $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 @@ class new_statement extends XMLDBAction {
         /// 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 8541160a18838430e7d733281ff43329ef6a5ff1..3a2a3be4080db017cafe5be2d4e8220d0ea84b25 100644 (file)
@@ -60,7 +60,7 @@ class new_table_from_mysql extends XMLDBAction {
         $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 @@ class new_table_from_mysql extends XMLDBAction {
         /// 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 @@ class new_table_from_mysql extends XMLDBAction {
             $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 @@ class new_table_from_mysql extends XMLDBAction {
                 }
             }
         /// 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 fdca79888eca577b7cf33be9f292e7414241986f..34cd5103a3d8e22f825f71c531fbb1f08e27370c 100644 (file)
@@ -58,10 +58,10 @@ class test extends XMLDBAction {
         $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 @@ class test extends XMLDBAction {
 
     /// 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 @@ class test extends XMLDBAction {
 
     /// 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 @@ class test extends XMLDBAction {
         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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
         $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
         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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
         /// 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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
         /// 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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
     /// 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 @@ class test extends XMLDBAction {
             }
 
         /// 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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
                         $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 @@ class test extends XMLDBAction {
             $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 @@ class test extends XMLDBAction {
             $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 c24cce12bb0d7fad5899d9ca111640798eb4faf2..c29f2d573b38a9544137400d81f2c3722bec423f 100644 (file)
@@ -63,49 +63,27 @@ class view_reserved_words extends XMLDBAction {
         $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 @@ class view_reserved_words extends XMLDBAction {
         $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 7165e5b50ff79ead8237a900fb0405443cc3b818..a49483abe2bad1c968f73f18289ec6093885e8b2 100644 (file)
@@ -58,7 +58,8 @@ class view_structure_sql extends XMLDBAction {
         $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 @@ class view_structure_sql extends XMLDBAction {
         }
     /// 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 @@ class view_structure_sql extends XMLDBAction {
         $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 7d1b46bbd014be33e99c456c73caf146482baa89..a891293f45574b3542c07ed1e4fff24be4ba44b2 100644 (file)
@@ -650,7 +650,7 @@ class view_table_php extends XMLDBAction {
 
     /**
      * 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 c2a281c8082ee7323387f2e5509b8a0d30ae23b9..e583b7d7230b6fbbf71ec10365d9950a945e0afe 100644 (file)
@@ -58,7 +58,8 @@ class view_table_sql extends XMLDBAction {
         $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 @@ class view_table_sql extends XMLDBAction {
 
     /// 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 @@ class view_table_sql extends XMLDBAction {
         $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 88ceae5a1d6b09dc609b93fb649a387325474f19..f57b8a1be3f3347da8ee2a24e1646f0f5d7582d4 100644 (file)
 /// 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
 /// 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 edeecb102d8b270cb6b5527d06284bcf852777f9..ae6686d155c2b54deb8c021d36c76b15867fee8a 100644 (file)
@@ -592,6 +592,10 @@ if ( !is_object($PHPCAS_CLIENT) ) {
                                  /// 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: move this to sql generators
+error('fix temporary table code in CAS');
+
         print "Configuring temp table\n";
         switch (strtolower($CFG->dbfamily)) {
             case 'mysql':
index e6b106d934d163d9a85bb8b793b07563577fd75f..9afd6cd717f1e577b6b5cf58da317a75b0627253 100644 (file)
@@ -532,6 +532,7 @@ class auth_plugin_ldap extends auth_plugin_base {
 
         // configure a temp table
         print "Configuring temp table\n";
+error('fix temporary table code in CAS'); // use sql generator
         switch (strtolower($CFG->dbfamily)) {
             case 'mysql':
                 $droptablesql[] = 'DROP TEMPORARY TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem)
@@ -556,6 +557,8 @@ class auth_plugin_ldap extends auth_plugin_base {
                 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 03319790f7790aa717716bdee1b55d65f1c6205d..303a42f0860e619cb341774385857b37dc1b13ff 100644 (file)
     /// 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
 
             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)) {
             $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 1fd18b60005442a0e2629f48677a40eee3999de8..28655379d9b924799d8cdd3c3a1fbb7c803e1398 100644 (file)
@@ -8,7 +8,7 @@ class block_admin extends block_list {
 
     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 @@ class block_admin extends block_list {
             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 544af38ee42ee3e62320def1b47aea40617861f8..39b38e4e28f1378b5580d7d219ae749b4efa13e6 100755 (executable)
 
         $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 8ca1eb0b88acc679ec95e8c4c1e226d79c2b74f1..3cf31e287e290c7f86100171499d09e981ffc5c4 100644 (file)
                         }
 
                         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 c8c4255312f1100e8f07082aa5a19b78e6747d35..9a3bc5373789578d5a8972727dd1d5d338d39cd0 100644 (file)
@@ -5,7 +5,7 @@ require_once($CFG->libdir.'/formslib.php');
 class course_edit_form extends moodleform {
 
     function definition() {
-        global $USER, $CFG;
+        global $USER, $CFG, $DB;
 
         $mform    =& $this->_form;
 
@@ -350,7 +350,7 @@ class course_edit_form extends moodleform {
             $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 b0b99798f009e745f09e6f4d0a0ef4d61b2229ea..7b3db0a5c6c82858584e9ba08cd43afe282efd12 100644 (file)
@@ -1535,7 +1535,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
  * @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 @@ function print_groupmode_setting($form, $course=NULL) {
  * 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 @@ function print_grouping_settings($form, $course=NULL) {
         $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 32c3e5b7e3ebcea8756b4023a086ea82b22a0e37..a0ab95156e19bb0c51af89ea19fcb1e3d7db6f4f 100644 (file)
@@ -19,7 +19,7 @@
 
 function xmldb_enrol_authorize_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
 
     $result = true;
 
index efd78a5604001f3b45c17151d17830d669bf5a81..6772374c076b82c87ceb0b185d28d14437737611 100644 (file)
--- a/file.php
+++ b/file.php
@@ -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');
     }
 
         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 d4a163a1d4c320f7e811411f8adb9324dcc12f4f..c38c891e00b04dfbf37062a64617d0d3d3d95e82 100644 (file)
@@ -175,7 +175,6 @@ if ($handle = fopen($imported_file['userfile']['tmp_name'], 'r')) {
         }
 
         //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 04ffdb18c36202b9e99535a5a6aacb484f49a873..e81561735c33dc88bba13838251bd6aab3c8ebd0 100644 (file)
@@ -28,7 +28,7 @@ $returnurl = $CFG->wwwroot.'/group/index.php?id='.$courseid;
 // 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 '<tr>'."\n";
 
 
 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 @@ if ($groups) {
             $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 a1f3705eaafe63da4b1f36ce88d52867c6e4b32c..77cd824ef8baa44ced45a98ac7d679eb830ae625 100644 (file)
@@ -43,7 +43,7 @@ if (empty($CFG->enablegroupings)) {
     $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 @@ if (empty($CFG->enablegroupings)) {
 }
 
 // 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 c038d330bd6afbd6a14a3e79457373a7bacbc862..6bde63c8ad35d5bc54aac7e06adaec56a16b9c67 100644 (file)
--- a/help.php
+++ b/help.php
@@ -193,9 +193,9 @@ function file_exists_and_readable($filepath) {
 // 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 0b5c9d41d5e47dd0bbfd7617aeed95c6c3052db9..6a66bb1e2ca6314502d224d62a71fc0e2c39cef8 100644 (file)
--- a/index.php
+++ b/index.php
 /// 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 b281e574b56bf99de4f31a5bac433b1ba32ad717..4332fe2b08cdb0aa1f32d28e08daa1645b830f06 100755 (executable)
@@ -155,7 +155,7 @@ define('ROLENAME_ORIGINAL', 0);// the name as defined in the role definition
 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 @@ $ACCESS = array(); // cache of caps for cron user switching and has_capability f
 $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 @@ function get_role_context_caps($roleid, $context) {
     $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 @@ function get_role_context_caps($roleid, $context) {
     // 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_context_caps($roleid, $context) {
  */
 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 @@ function get_role_access($roleid, $accessdata=NULL) {
     //
     $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 @@ function get_role_access($roleid, $accessdata=NULL) {
 
         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 @@ function get_role_access($roleid, $accessdata=NULL) {
         }
         
     } 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_role_access($roleid, $accessdata=NULL) {
  */
 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 @@ function get_default_frontpage_role_access($roleid, $accessdata=NULL) {
     //
     $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 @@ function get_default_frontpage_role_access($roleid, $accessdata=NULL) {
  * @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 @@ function get_guest_role() {
             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 @@ function get_guest_role() {
  * @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 @@ function has_capability($capability, $context, $userid=NULL, $doanything=true) {
         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 @@ function has_any_capability($capabilities, $context, $userid=NULL, $doanything=t
  * @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 aggregate_roles_from_accessdata($context, $accessdata) {
 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 @@ function require_capability($capability, $context, $userid=NULL, $doanything=tru
             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 require_capability($capability, $context, $userid=NULL, $doanything=tru
  */
 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 @@ function get_user_courses_bycap($userid, $cap, $accessdata, $doanything, $sort='
                        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 @@ function get_user_courses_bycap($userid, $cap, $accessdata, $doanything, $sort='
         // - 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 @@ function get_user_courses_bycap($userid, $cap, $accessdata, $doanything, $sort='
                        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_courses_bycap($userid, $cap, $accessdata, $doanything, $sort='
  */
 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 @@ function get_user_access_sitewide($userid) {
     // 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 @@ function get_user_access_sitewide($userid) {
     $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 @@ function get_user_access_sitewide($userid) {
             }
         }
         unset($ra);
-        rs_close($rs);
+        $rs->close();
     }
 
     // Walk up the tree to grab all the roledefs
@@ -1147,31 +1160,32 @@ function get_user_access_sitewide($userid) {
     // 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 @@ function get_user_access_sitewide($userid) {
     $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 get_user_access_sitewide($userid) {
  */
 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 @@ function load_subcontext($userid, $context, &$accessdata) {
     // 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 @@ function load_subcontext($userid, $context, &$accessdata) {
         $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 load_subcontext($userid, $context, &$accessdata) {
  */
 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 @@ function get_role_access_bycontext($roleid, $context, $accessdata=NULL) {
     // 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 ";
-
-    $rs = get_recordset_sql($sql);
-    while ($rd = rs_fetch_next_record($rs)) {
-        $k = "{$rd->path}:{$roleid}";
-        $accessdata['rdef'][$k][$rd->capability] = $rd->permission;
+              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."/%");
+
+    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 load_all_capabilities() {
  *
  */
 function reload_all_capabilities() {
-    global $USER,$CFG;
+    global $USER, $DB;
 
     // error_log("reloading");
     // copy switchroles
@@ -1569,13 +1587,13 @@ function reload_all_capabilities() {
     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 reload_all_capabilities() {
  */
 function load_temp_role($context, $roleid, $accessdata) {
 
-    global $CFG;
+    global $CFG, $DB;
 
     //
     // Load rdefs for the role in -
@@ -1599,21 +1617,22 @@ function load_temp_role($context, $roleid, $accessdata) {
     $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 @@ function check_enrolment_plugins(&$user) {
 
 /**
  * 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 @@ function moodle_install_roles() {
         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 @@ function moodle_install_roles() {
     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 @@ function get_local_override($roleid, $contextid, $capability) {
  * @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 @@ function create_role($name, $shortname, $description, $legacy='') {
     $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 @@ function create_role($name, $shortname, $description, $legacy='') {
         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 @@ function create_role($name, $shortname, $description, $legacy='') {
  * @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 @@ function delete_role($roleid) {
 
     $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 @@ function delete_role($roleid) {
                                      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 delete_role($roleid) {
  */
 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 @@ function assign_capability($capability, $permission, $roleid, $contextid, $overw
 
     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 @@ function assign_capability($capability, $permission, $roleid, $contextid, $overw
  * @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 unassign_capability($capability, $roleid, $contextid=NULL) {
  */
 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 @@ function get_roles_with_capability($capability, $permission=NULL, $context='') {
             $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 @@ function get_roles_with_capability($capability, $permission=NULL, $context='') {
     $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 @@ function get_roles_with_capability($capability, $permission=NULL, $context='') {
  * @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 @@ function role_assign($roleid, $userid, $groupid, $contextid, $timestart=0, $time
 
 /// 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 @@ function role_assign($roleid, $userid, $groupid, $contextid, $timestart=0, $time
         $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 @@ function role_assign($roleid, $userid, $groupid, $contextid, $timestart=0, $time
         $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 @@ function role_assign($roleid, $userid, $groupid, $contextid, $timestart=0, $time
 
     /// 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 10645ee5cfb3ffc987e799fc0f28723621bf080c..994baef1be1c3e95bbe676853b611fbc28a7a697 100644 (file)
@@ -42,14 +42,13 @@ function upgrade_blocks_savepoint($result, $version, $type) {
 /**
  * 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 @@ function upgrade_plugins($type, $dir, $return) {
             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 @@ function upgrade_plugins($type, $dir, $return) {
             /// 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 @@ function upgrade_plugins($type, $dir, $return) {
                 $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 @@ function upgrade_plugins($type, $dir, $return) {
                              $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 @@ function upgrade_plugins($type, $dir, $return) {
 /**
  * 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 @@ function upgrade_activity_modules($return) {
 
         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 @@ function upgrade_activity_modules($return) {
                 $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 @@ function upgrade_activity_modules($return) {
                              $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 @@ function upgrade_activity_modules($return) {
             $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 @@ function upgrade_activity_modules($return) {
  * @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 @@ function set_cron_lock($name, $until, $ignorecurrent=false) {
 
     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 @@ function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext=''
         }
 
         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 upgrade_get_javascript() {
 }
 
 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 @@ function create_admin_user($user_input=NULL) {
         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 @@ class admin_setting_sitesetselect extends admin_setting_configselect {
     }
 
     function write_setting($data) {
+        global $DB;
         if (!in_array($data, array_keys($this->choices))) {
             return get_string('errorsetting', 'admin');
         }
@@ -2439,7 +2439,7 @@ class admin_setting_sitesetselect extends admin_setting_configselect {
         $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 @@ class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
     }
 
     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 @@ class admin_setting_sitesettext extends admin_setting_configtext {
     }
 
     function write_setting($data) {
+        global $DB;
         $data = trim($data);
         $validated = $this->validate($data); 
         if ($validated !== true) {
@@ -2577,9 +2579,9 @@ class admin_setting_sitesettext extends admin_setting_configtext {
 
         $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 @@ class admin_setting_special_frontpagedesc extends admin_setting {
     }
 
     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 @@ class admin_setting_special_gradebookroles extends admin_setting_configmultichec
     }
 
     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_special_gradebookroles extends admin_setting_configmultichec
 
 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 @@ class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
 
         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 @@ class admin_setting_special_coursemanager extends admin_setting_configmulticheck
     }
 
     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 @@ class admin_page_managemods extends admin_externalpage {
     }
 
     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 @@ class admin_page_manageblocks extends admin_externalpage {
     }
 
     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 @@ function admin_apply_default_settings($node=NULL, $unconditional=true) {
  * @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 @@ function admin_write_settings($formdata) {
     }
 
     // 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 @@ function any_new_admin_settings($node) {
 
 /**
  * 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 @@ function db_replace($search, $replace) {
  * distribution or not.
  */
 function print_plugin_tables() {
+    global $DB;
     $plugins_standard = array();
     $plugins_standard['mod'] = array('assignment',
                                      'chat',
@@ -4571,8 +4577,8 @@ function print_plugin_tables() {
                                         '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 f4e497f34b4abb41949cde016fb0a23c24c246df..9dbdab1d30442ddc77120583b875cc8ecead4480 100644 (file)
@@ -1036,7 +1036,7 @@ function upgrade_blocks_db($continueto) {
 /// 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 @@ function upgrade_blocks_db($continueto) {
         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 @@ function upgrade_blocks_db($continueto) {
         $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 @@ function upgrade_blocks_db($continueto) {
                      '/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 @@ function upgrade_blocks_db($continueto) {
 //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 @@ function upgrade_blocks_plugins($continueto) {
                 $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 @@ function upgrade_blocks_plugins($continueto) {
                              $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 @@ function upgrade_blocks_plugins($continueto) {
             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 @@ function upgrade_blocks_plugins($continueto) {
         /// 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 4816efc7aa221f1d165baf9e65d2651cc22fdf83..7ccb47b9469168e35780153b7d65e5989323323d 100644 (file)
@@ -1865,7 +1865,7 @@ function add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user
     // 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 @@ function add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user
     }
     $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 add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user
  */
 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 @@ function user_accesstime_log($courseid=0) {
     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 @@ function user_accesstime_log($courseid=0) {
 
 /// 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();
-        }
 
-    /// Update course lastaccess for next checks
-        $USER->currentcourseaccess[$courseid] = $timenow;
-        if (defined('MDL_PERFDB')) { global $PERF ; $PERF->dbqueries++; };
+        $lastaccess = $DB->get_field('user_lastaccess', 'timeaccess', array('userid'=>$USER->id, 'courseid'=>$courseid));
 
-        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 8d7c29e6ca69510087f1e5b549d01321edc2374a..a9aa762bbdeb790c923594a79af0a367b8fb3351 100644 (file)
@@ -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"
 >
         <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"/>
         <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 2ade4db902e6ca4ce256638830010c27808689d0..d7d58ca5e0d15773f6b2e9d9825a1367fef8e543 100644 (file)
 
 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 @@ function xmldb_main_upgrade($oldversion=0) {
         $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 @@ function xmldb_main_upgrade($oldversion=0) {
         $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 @@ function xmldb_main_upgrade($oldversion=0) {
 
     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 @@ function xmldb_main_upgrade($oldversion=0) {
         $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 @@ function xmldb_main_upgrade($oldversion=0) {
         $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 1b68b00889d67e94cf778ceac02aa0d389d47d95..ced4b2897d42b4dc4262fc48525e2ad23bfe8a91 100644 (file)
@@ -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 @@ function upgrade_fix_category_depths() {
             break;
         }
     }
-    $db->debug = true;
 }
 
 ?>
diff --git a/lib/ddl/database_manager.php b/lib/ddl/database_manager.php
new file mode 100644 (file)
index 0000000..c47f155
--- /dev/null
@@ -0,0 +1,1138 @@
+<?php // $Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// 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);
+    }
+}
+
+?>
similarity index 77%
rename from lib/xmldb/classes/generators/mssql/mssql.class.php
rename to lib/ddl/mssql_sql_generator.php
index 4bdd00ebde43298989258cb17340b1b8deabc522..f27a86ff790e751f4c0d167b569ee3d8955de2a7 100644 (file)
 //                                                                       //
 ///////////////////////////////////////////////////////////////////////////
 
+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 XMLDBmssql extends XMLDBgenerator {
+class mssql_sql_generator extends sql_generator {
 
 /// 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
+    public $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
+    public $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)
+    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)
 
-    var $specify_nulls = true;  //To force the generator if NULL clauses must be specified. It shouldn't be necessary
+    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 :-(
 
-    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
+    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
 
-    var $enum_inline_code = false; //Does the generator need to add inline code in the column definition
+    public $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
+    public $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
+    public $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
+    public $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'";
+    public $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
+    public $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
+    public $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
+    public $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();
+    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
      */
-    function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
+    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
@@ -144,7 +189,7 @@ class XMLDBmssql extends XMLDBgenerator {
     /**
      * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
      */
-    function getEnumExtraSQL ($xmldb_table, $xmldb_field) {
+    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()) . '))';
@@ -157,7 +202,7 @@ class XMLDBmssql extends XMLDBgenerator {
      * 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) {
+    public function getDropFieldSQL($xmldb_table, $xmldb_field) {
 
         global $db;
 
@@ -189,7 +234,7 @@ class XMLDBmssql extends XMLDBgenerator {
      * 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) {
+    public function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
 
         $results = array();  //Array where all the sentences will be stored
 
@@ -218,7 +263,7 @@ class XMLDBmssql extends XMLDBgenerator {
     /**
      * Returns the code (array of statements) needed to execute extra statements on field rename
      */
-    function getRenameFieldExtraSQL ($xmldb_table, $xmldb_field, $newname) {
+    public function getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname) {
 
         $results = array();
 
@@ -240,7 +285,7 @@ class XMLDBmssql extends XMLDBgenerator {
     /**
      * Returns the code (array of statements) needed to execute extra statements on table rename
      */
-    function getRenameTableExtraSQL ($xmldb_table, $newname) {
+    public function getRenameTableExtraSQL($xmldb_table, $newname) {
 
         $results = array();
 
@@ -271,21 +316,21 @@ class XMLDBmssql extends XMLDBgenerator {
     /**
      * 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;
+    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 = $this->getTableName($xmldb_table);
-        $fieldname = $this->getEncQuoted($xmldb_field->getName());
+        $tablename = $xmldb_table->getName();
+        $fieldname = $xmldb_field->getName();
 
     /// Take a look to field metadata
-        $meta = array_change_key_case($db->MetaColumns($tablename));
+        $this->mdb->reset_columns($tablename);
+
+        $meta = $this->mdb->get_columns($tablename);
         $metac = $meta[$fieldname];
-        $oldtype = strtolower($metac->type);
-        $oldmetatype = column_type($xmldb_table->getName(), $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;
@@ -295,11 +340,11 @@ class XMLDBmssql extends XMLDBgenerator {
         $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') ||
+        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    && substr($oldmetatype, 0, 1) == 'C') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && substr($oldmetatype, 0, 1) == 'X') ||
+            ($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;
         }
@@ -331,20 +376,17 @@ class XMLDBmssql extends XMLDBgenerator {
     /**
      * 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) {
+    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();
 
-    /// 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
+            $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 {
@@ -356,10 +398,10 @@ class XMLDBmssql extends XMLDBgenerator {
     }
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum 
+     * 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) {
+    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));
@@ -369,7 +411,7 @@ class XMLDBmssql extends XMLDBgenerator {
      * 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) {
+    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)
@@ -383,10 +425,10 @@ class XMLDBmssql extends XMLDBgenerator {
     }
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default 
+     * 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) {
+    public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
     /// MSSQL is a bit special and it requires the corresponding DEFAULT CONSTRAINT to be dropped
 
         $results = array();
@@ -396,19 +438,21 @@ class XMLDBmssql extends XMLDBgenerator {
         $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)) {
+        $default_clause = $this->getDefaultClause($xmldb_field);
+        if ($default_clause) {
         /// We need to build the default (Moodle) default, so do it
-            $results[] = 'ALTER TABLE ' . $tablename . ' ADD' . $default_clause . ' FOR ' . $fieldname;
+            $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 
+     * 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) {
+    public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
     /// MSSQL is a bit special and it requires the corresponding DEFAULT CONSTRAINT to be dropped
 
         $results = array();
@@ -420,7 +464,7 @@ class XMLDBmssql extends XMLDBgenerator {
     /// 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;
     }
@@ -430,7 +474,7 @@ class XMLDBmssql extends XMLDBgenerator {
      * or false if not found
      * This function should be considered internal and never used outside from generator
      */
-    function getDefaultConstraintName($xmldb_table, $xmldb_field) {
+    public function getDefaultConstraintName($xmldb_table, $xmldb_field) {
 
     /// Get the quoted name of the table and field
         $tablename = $this->getTableName($xmldb_table);
@@ -455,7 +499,7 @@ class XMLDBmssql extends XMLDBgenerator {
      * 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) {
+    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
 
         $results = array();
 
@@ -498,7 +542,7 @@ class XMLDBmssql extends XMLDBgenerator {
      * return if such name is currently in use (true) or no (false)
      * (invoked from getNameForObject()
      */
-    function isNameInUse($object_name, $type, $table_name) {
+    public function isNameInUse($object_name, $type, $table_name) {
         switch($type) {
             case 'seq':
             case 'trg':
@@ -506,15 +550,15 @@ class XMLDBmssql extends XMLDBgenerator {
             case 'uk':
             case 'fk':
             case 'ck':
-                if ($check = get_records_sql("SELECT name 
-                                              FROM sysobjects 
+                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 
+                if ($check = get_records_sql("SELECT name
                                               FROM sysindexes
                                               WHERE lower(name) = '" . strtolower($object_name) . "'")) {
                     return true;
@@ -524,10 +568,23 @@ class XMLDBmssql extends XMLDBgenerator {
         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
      */
-    function getReservedWords() {
+    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 (
similarity index 76%
rename from lib/xmldb/classes/generators/mysql/mysql.class.php
rename to lib/ddl/mysql_sql_generator.php
index 69f43f6df4b7c0a7bd78cd355881cc5cfd980d03..d9de79fad1caf327e52d96d94ccaa95f7b3863a6 100644 (file)
 //                                                                       //
 ///////////////////////////////////////////////////////////////////////////
 
+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 XMLDBmysql extends XMLDBGenerator {
+class mysql_sql_generator extends sql_generator {
 
 /// Only set values that are different from the defaults present in XMLDBgenerator
 
-    var $quote_string = '`';   // String used to quote names
+    public $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)
+    public $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
+    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
 
-    var $primary_key_name = ''; //To force primary key names to one string (null=no force)
+    public $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
+    public $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
+    public $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
+    public $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
+    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
 
-    var $enum_extra_code = false; //Does the generator need to add extra code to generate code for the enums in the table
+    public $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
+    public $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
+    public $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
+    public $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
+    public $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!)
+    public $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!)
+    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
      */
-    function XMLDBmysql() {
-        parent::XMLDBGenerator();
-        global $CFG;
-        $this->prefix = '';
-        $this->reserved_words = $this->getReservedWords();
+    public function __construct($mdb) {
+        parent::__construct($mdb);
     }
 
     /**
      * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
      */
-    function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
+    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!
@@ -167,28 +166,28 @@ class XMLDBmysql extends XMLDBGenerator {
     }
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum 
+     * 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) {
+    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 
+    /**
+     * 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) {
+    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 
+     * 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) {
+    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);
@@ -199,9 +198,7 @@ class XMLDBmysql extends XMLDBGenerator {
      * 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
+    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);
@@ -209,17 +206,18 @@ class XMLDBmysql extends XMLDBGenerator {
     /// 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);
+        $fieldsql = $this->getFieldSQL($xmldb_field_clone);
+
+        $sql = 'ALTER TABLE ' . $this->getTableName($xmldb_table) . ' CHANGE ' . $fieldsql;
 
-        return $results;
+        return array($sql);
     }
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default 
+     * 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) {
+    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);
@@ -228,7 +226,7 @@ class XMLDBmysql extends XMLDBGenerator {
     /**
      * Given one XMLDB Field, return its enum SQL
      */
-    function getEnumSQL ($xmldb_field) {
+    public function getEnumSQL($xmldb_field) {
         return 'enum(' . implode(', ', $xmldb_field->getEnumValues()) . ')';
     }
 
@@ -236,12 +234,11 @@ class XMLDBmysql extends XMLDBGenerator {
      * 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)) . "'";
+            $comment .= " COMMENT='" . $this->addslashes(substr($xmldb_table->getComment(), 0, 60)) . "'";
         }
         return array($comment);
     }
@@ -256,18 +253,37 @@ class XMLDBmysql extends XMLDBGenerator {
      * 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) {
+    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
 
         global $db;
 
-        $results = array();
+        $tablename = $xmldb_table->getName($xmldb_table);
 
-        $tablename = $this->getTableName($xmldb_table);
+        $this->mdb->reset_columns($tablename);
 
     /// Fetch all the columns in the table
-        if ($columns = $db->MetaColumns($tablename)) {
-        /// Normalize array keys
-            $columns = array_change_key_case($columns, CASE_LOWER);
+        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
@@ -278,20 +294,8 @@ class XMLDBmysql extends XMLDBGenerator {
                     $results[$key] = $result;
                 }
             }
+            return $results;
         }
-
-    /// 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;
     }
 
     /**
@@ -299,28 +303,22 @@ class XMLDBmysql extends XMLDBGenerator {
      * return if such name is currently in use (true) or no (false)
      * (invoked from getNameForObject()
      */
-    function isNameInUse($object_name, $type, $table_name) {
-
-        global $db;
+    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 = $db->MetaTables();
-                $metatables = array_flip($metatables);
-                $metatables = array_change_key_case($metatables, CASE_LOWER);
-                if (array_key_exists($tname,  $metatables)) {
+                $metatables = $this->mdb->get_tables();
+                if (isset($metatables[$tname])) {
                 /// Fetch all the indexes in the table
-                    if ($indexes = $db->MetaIndexes($tname)) {
-                    /// Normalize array keys
-                        $indexes = array_change_key_case($indexes, CASE_LOWER);
+                    if ($indexes = $this->mdb->get_indexes($tname)) {
                     /// Look for existing index in array
-                        if (array_key_exists(strtolower($object_name), $indexes)) {
+                        if (isset($indexes[$object_name])) {
                             return true;
                         }
                     }
@@ -334,7 +332,7 @@ class XMLDBmysql extends XMLDBGenerator {
     /**
      * Returns an array of reserved words (lowercase) for this DB
      */
-    function getReservedWords() {
+    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 (
similarity index 82%
rename from lib/xmldb/classes/generators/oci8po/oci8po.class.php
rename to lib/ddl/oracle_sql_generator.php
index 05bed29baa182e10a31c59dec81c033621315173..387b4f61dca6852be96cf198eda91fc08df98c44 100644 (file)
 //                                                                       //
 ///////////////////////////////////////////////////////////////////////////
 
+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 XMLDBoci8po extends XMLDBgenerator {
+class oracle_sql_generator extends sql_generator {
 
 /// 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
+    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)
 
-    var $number_type = 'NUMBER';    // Proper type for NUMBER(x) in this DB
+    public $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)
+    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! :-(
 
-    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
+    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
 
-    var $rename_table_extra_code = true; //Does the generator need to add code after table rename
+    public $default_after_null = false;  //To decide if the default clause of each field must go after the null clause
 
-    var $rename_column_extra_code = true; //Does the generator need to add code after field rename
+    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
 
-    var $enum_inline_code = false; //Does the generator need to add inline code in the column definition
+    public $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
+    public $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();
+    public function __construct($mdb) {
+        parent::__construct($mdb);
     }
 
     /**
      * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
      */
-    function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
+    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
@@ -117,10 +111,54 @@ class XMLDBoci8po extends XMLDBgenerator {
         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
      */
-    function getEnumExtraSQL ($xmldb_table, $xmldb_field) {
+    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()) . '))';
@@ -131,7 +169,7 @@ class XMLDBoci8po extends XMLDBgenerator {
     /**
      * Returns the code needed to create one sequence for the xmldb_table and xmldb_field passes
      */
-    function getCreateSequenceSQL ($xmldb_table, $xmldb_field) {
+    public function getCreateSequenceSQL($xmldb_table, $xmldb_field) {
 
         $results = array();
 
@@ -152,7 +190,7 @@ class XMLDBoci8po extends XMLDBgenerator {
     /**
      * Returns the code needed to create one trigger for the xmldb_table and xmldb_field passed
      */
-    function getCreateTriggerSQL ($xmldb_table, $xmldb_field) {
+    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');
@@ -174,7 +212,7 @@ class XMLDBoci8po extends XMLDBgenerator {
      * 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) {
+    public function getDropSequenceSQL($xmldb_table, $xmldb_field, $include_trigger=false) {
 
         $sequence_name = $this->getSequenceFromDB($xmldb_table);
 
@@ -198,7 +236,7 @@ class XMLDBoci8po extends XMLDBgenerator {
     function getCommentSQL ($xmldb_table) {
 
         $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
-        $comment.= " IS '" . addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
+        $comment.= " IS '" . $this->addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
 
         return array($comment);
     }
@@ -206,7 +244,7 @@ class XMLDBoci8po extends XMLDBgenerator {
     /**
      * Returns the code (array of statements) needed to execute extra statements on field rename
      */
-    function getRenameFieldExtraSQL ($xmldb_table, $xmldb_field, $newname) {
+    public function getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname) {
 
         $results = array();
 
@@ -227,7 +265,7 @@ class XMLDBoci8po extends XMLDBgenerator {
     /**
      * Returns the code (array of statements) needed to execute extra statements on table drop
      */
-    function getDropTableExtraSQL ($xmldb_table) {
+    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);
     }
@@ -235,7 +273,7 @@ class XMLDBoci8po extends XMLDBgenerator {
     /**
      * Returns the code (array of statements) needed to execute extra statements on table rename
      */
-    function getRenameTableExtraSQL ($xmldb_table, $newname) {
+    public function getRenameTableExtraSQL($xmldb_table, $newname) {
 
         $results = array();
 
@@ -287,7 +325,7 @@ class XMLDBoci8po extends XMLDBgenerator {
      *     - 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) {
+    public function getAlterFieldSQL($xmldb_table, $xmldb_field) {
 
         global $db;
 
@@ -298,10 +336,10 @@ class XMLDBoci8po extends XMLDBgenerator {
         $fieldname = $this->getEncQuoted($xmldb_field->getName());
 
     /// Take a look to field metadata
-        $meta = array_change_key_case($db->MetaColumns($tablename));
+        $meta = $this->mdb->get_columns($tablename);
         $metac = $meta[$fieldname];
-        $oldtype = strtolower($metac->type);
-        $oldmetatype = column_type($xmldb_table->getName(), $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
@@ -328,14 +366,14 @@ class XMLDBoci8po extends XMLDBgenerator {
         $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') ||
+        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    && substr($oldmetatype, 0, 1) == 'C') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && substr($oldmetatype, 0, 1) == 'X') ||
+            ($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) ||
@@ -421,8 +459,11 @@ class XMLDBoci8po extends XMLDBgenerator {
         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 ($from_temp_fields) {
+                $default_clause = $this->getDefaultClause($xmldb_field);
+                if ($default_clause) {
+                    $this->alter_column_skip_default = false;
+                }
             }
         }
 
@@ -437,51 +478,51 @@ class XMLDBoci8po extends XMLDBgenerator {
     }
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum 
+     * 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) {
+    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) . 
+        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 
+
+    /**
+     * 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) {
+     */
+    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) . 
+            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 
+     * 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) {
+    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 
+
+    /**
+     * 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) {
+     */
+    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
@@ -491,7 +532,7 @@ class XMLDBoci8po extends XMLDBgenerator {
      * 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) {
+    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
 
         $results = array();
 
@@ -533,7 +574,7 @@ class XMLDBoci8po extends XMLDBgenerator {
      * independent elements)
      * If no sequence is found, returns false
      */
-    function getSequenceFromDB($xmldb_table) {
+    public function getSequenceFromDB($xmldb_table) {
 
          $tablename    = strtoupper($this->getTableName($xmldb_table));
          $prefixupper  = strtoupper($this->prefix);
@@ -558,7 +599,7 @@ class XMLDBoci8po extends XMLDBgenerator {
      * in the table (fetched from DB)
      * If no trigger is found, returns false
      */
-    function getTriggerFromDB($xmldb_table) {
+    public function getTriggerFromDB($xmldb_table) {
 
         $tablename   = strtoupper($this->getTableName($xmldb_table));
         $prefixupper = strtoupper($this->prefix);
@@ -579,14 +620,14 @@ class XMLDBoci8po extends XMLDBgenerator {
      * return if such name is currently in use (true) or no (false)
      * (invoked from getNameForObject()
      */
-    function isNameInUse($object_name, $type, $table_name) {
+    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 
+                if ($check = get_records_sql("SELECT object_name
+                                              FROM user_objects
                                               WHERE lower(object_name) = '" . strtolower($object_name) . "'")) {
                     return true;
                 }
@@ -595,7 +636,7 @@ class XMLDBoci8po extends XMLDBgenerator {
             case 'uk':
             case 'fk':
             case 'ck':
-                if ($check = get_records_sql("SELECT constraint_name 
+                if ($check = get_records_sql("SELECT constraint_name
                                               FROM user_constraints
                                               WHERE lower(constraint_name) = '" . strtolower($object_name) . "'")) {
                     return true;
@@ -605,10 +646,16 @@ class XMLDBoci8po extends XMLDBgenerator {
         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
      */
-    function getReservedWords() {
+    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 (
similarity index 83%
rename from lib/xmldb/classes/generators/postgres7/postgres7.class.php
rename to lib/ddl/postgres_sql_generator.php
index 0eb8dd2560b7a3a2f02c4954f8f0637d6621fb6d..f231be4c4b0b66ab2861fe5e63e71e61ebf880f8 100644 (file)
 //                                                                       //
 ///////////////////////////////////////////////////////////////////////////
 
+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 XMLDBpostgres7 extends XMLDBgenerator {
+class postgres_sql_generator extends sql_generator {
 
 /// 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)
+    public $number_type = 'NUMERIC';    // Proper type for NUMBER(x) in this DB
 
-    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
+    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)
 
-    var $rename_table_extra_code = true; //Does the generator need to add code after table rename
+    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
 
-    var $rename_column_extra_code = true; //Does the generator need to add code after column rename
+    public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
 
-    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
+    public $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!)
+    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
      */
-    function XMLDBpostgres7() {
-        parent::XMLDBgenerator();
-        $this->prefix = '';
-        $this->reserved_words = $this->getReservedWords();
+    public function __construct($mdb) {
+        parent::__construct($mdb);
     }
 
     /**
      * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
      */
-    function getTypeSQL ($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
+    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
@@ -122,7 +118,7 @@ class XMLDBpostgres7 extends XMLDBgenerator {
     /**
      * Returns the code needed to create one enum for the xmldb_table and xmldb_field passes
      */
-    function getEnumExtraSQL ($xmldb_table, $xmldb_field) {
+    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()) . '))';
@@ -136,7 +132,7 @@ class XMLDBpostgres7 extends XMLDBgenerator {
     function getCommentSQL ($xmldb_table) {
 
         $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
-        $comment.= " IS '" . addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
+        $comment.= " IS '" . $this->addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
 
         return array($comment);
     }
@@ -144,7 +140,7 @@ class XMLDBpostgres7 extends XMLDBgenerator {
     /**
      * Returns the code (array of statements) needed to execute extra statements on table rename
      */
-    function getRenameTableExtraSQL ($xmldb_table, $newname) {
+    public function getRenameTableExtraSQL($xmldb_table, $newname) {
 
         $results = array();
 
@@ -184,17 +180,17 @@ class XMLDBpostgres7 extends XMLDBgenerator {
      * 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) {
-    
+    public function getAddFieldSQL($xmldb_table, $xmldb_field) {
+
         $results = array();
 
         $tablename = $this->getTableName($xmldb_table);
         $fieldname = $this->getEncQuoted($xmldb_field->getName());
 
-        $defaultvalue = null;
+        $defaultvalue = $xmldb_field->getDefault();
 
     /// Save old flags
         $old_skip_default = $this->alter_column_skip_default;
@@ -211,13 +207,19 @@ class XMLDBpostgres7 extends XMLDBgenerator {
 
     /// 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
+            $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) {
-                $results[] = 'UPDATE ' . $tablename . ' SET ' . $fieldname . '=' . $defaultvalue;
+                if (!is_numeric($defaultvalue)) {
+                    $defaultvalue = "'".$this->addslashes($defaultvalue)."'";
+                }
+                $sql = 'UPDATE ' . $tablename . ' SET ' . $fieldname . '=' . $defaultvalue;
+                $results[] = $sql;
             }
         }
 
@@ -235,30 +237,29 @@ class XMLDBpostgres7 extends XMLDBgenerator {
      * 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 
+     *       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) {
+    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());
+    /// Get the normla names of the table and field
+        $tablename = $xmldb_table->getName();
+        $fieldname = $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);
+        $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 : strtok($metac->default_value, ':');
+        $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
@@ -269,15 +270,15 @@ class XMLDBpostgres7 extends XMLDBgenerator {
         $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') ||
+        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    && substr($oldmetatype, 0, 1) == 'C') ||
-            ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && substr($oldmetatype, 0, 1) == 'X') ||
+            ($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 
+    /// Detect if we are changing the precision
         if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
             ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
             ($oldlength == -1) ||
@@ -296,8 +297,7 @@ class XMLDBpostgres7 extends XMLDBgenerator {
         }
     /// 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
+            ($xmldb_field->getDefault() === $olddefault)) {
             $defaultchanged = false;
         }
     /// Detect if we are changing the nullability
@@ -305,6 +305,10 @@ class XMLDBpostgres7 extends XMLDBgenerator {
             $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
@@ -348,8 +352,10 @@ class XMLDBpostgres7 extends XMLDBgenerator {
         }
     /// 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
+            $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
@@ -365,14 +371,14 @@ class XMLDBpostgres7 extends XMLDBgenerator {
             }
         }
 
-    /// Return the results 
+    /// 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) {
+    public function getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname) {
 
         $results = array();
 
@@ -391,20 +397,20 @@ class XMLDBpostgres7 extends XMLDBgenerator {
     }
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its enum 
+     * 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) {
+    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 
+     * 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) {
+    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)
@@ -418,20 +424,20 @@ class XMLDBpostgres7 extends XMLDBgenerator {
     }
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to create its default 
+     * 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) {
+    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 
+     * 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) {
+    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);
@@ -445,7 +451,7 @@ class XMLDBpostgres7 extends XMLDBgenerator {
      * 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) {
+    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
 
         $results = array();
 
@@ -488,7 +494,7 @@ class XMLDBpostgres7 extends XMLDBgenerator {
 /**
  * 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: 
+ * 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
@@ -513,13 +519,13 @@ function getSequenceFromDB($xmldb_table) {
      * return if such name is currently in use (true) or no (false)
      * (invoked from getNameForObject()
      */
-    function isNameInUse($object_name, $type, $table_name) {
+    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 
+                if ($check = get_records_sql("SELECT relname
+                                              FROM pg_class
                                               WHERE lower(relname) = '" . strtolower($object_name) . "'")) {
                     return true;
                 }
@@ -528,14 +534,14 @@ function getSequenceFromDB($xmldb_table) {
             case 'uk':
             case 'fk':
             case 'ck':
-                if ($check = get_records_sql("SELECT conname 
+                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 
+                if ($check = get_records_sql("SELECT tgname
                                               FROM pg_trigger
                                               WHERE lower(tgname) = '" . strtolower($object_name) . "'")) {
                     return true;
@@ -548,7 +554,7 @@ function getSequenceFromDB($xmldb_table) {
     /**
      * Returns an array of reserved words (lowercase) for this DB
      */
-    function getReservedWords() {
+    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 (
similarity index 73%
rename from lib/xmldb/classes/generators/XMLDBGenerator.class.php
rename to lib/ddl/sql_generator.php
index 55822491a3cdb36d6c16dc55fa50fa139a8848ee..4242c657222711446b5e90e7adc5fba1ec9d0136 100644 (file)
@@ -7,7 +7,7 @@
 // Moodle - Modular Object-Oriented Dynamic Learning Environment         //
 //          http://moodle.com                                            //
 //                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas        http://dougiamas.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  //
 /// The rest of classes will inherit, by default, the same logic.
 /// Functions will be overriden as needed to generate correct SQL.
 
-class XMLDBgenerator {
+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.
 
-    var $quote_string = '"';   // String used to quote names
+    public $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
+    public $statement_end = ';'; // String to be automatically added at the end of each statement
 
-    var $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
 
-    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...)
+    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...)
 
-    var $number_type = 'NUMERIC';    // Proper type for NUMBER(x) in this DB
+    public $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)
+    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)
 
-    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
+    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
 
-    var $default_after_null = true;  //To decide if the default clause of each field must go after the null clause
+    public $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
+    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 :-(
 
-    var $primary_key_name = null; //To force primary key names to one string (null=no force)
+    public $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
+    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
 
-    var $drop_primary_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop PKs
+    public $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
+    public $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
+    public $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
+    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
 
-    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
+    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
 
-    var $add_table_comments  = true;  // Does the generator need to add code for table comments
+    public $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
+    public $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
+    public $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!)
+    public $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
+    public $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
+    public $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
+    public $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
+    public $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
+    public $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
+    public $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
+    public $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';
+    public $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
+    public $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
+    public $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
+    public $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
+    public $prefix;         // Prefix to be used for all the DB objects
+
+    public $reserved_words; // List of reserved words (in order to quote them properly)
 
-    var $reserved_words; // List of reserved words (in order to quote them properly)
+    public $mdb;
 
     /**
-     * Creates one new XMLDBGenerator
+     * Creates new sql_generator
+     * @param object moodle_database instance
      */
-    function XMLDBgenerator() {
-        global $CFG;
-        $this->prefix = '';
+    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
     }
 
-/// ALL THESE FUNCTION ARE SHARED BY ALL THE XMLDGenerator classes
+    /**
+     * 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;
+        }
+    }
 
     /**
-     * Set the prefix
+     * This function will return the SQL code needed to create db tables and statements
      */
-    function setPrefix($prefix) {
-        if ($this->prefix_on_names) { // Only if we want prefix on names
-            $this->prefix = $prefix;
+    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;
     }
 
     /**
@@ -156,16 +204,11 @@ class XMLDBgenerator {
      * @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 = '';
-        }
+    public function getTableName($xmldb_table, $quoted=true) {
     /// Get the name
-        $tablename = $prefixtouse . $xmldb_table->getName();
-    /// Apply quotes conditionally
+        $tablename = $this->prefix.$xmldb_table->getName();
+
+    /// Apply quotes optionally
         if ($quoted) {
             $tablename = $this->getEncQuoted($tablename);
         }
@@ -177,7 +220,7 @@ class XMLDBgenerator {
      * Given one correct XMLDBTable, returns the SQL statements
      * to create it (inside one array)
      */
-    function getCreateTableSQL($xmldb_table) {
+    public function getCreateTableSQL($xmldb_table) {
 
         $results = array();  //Array where all the sentences will be stored
 
@@ -188,12 +231,6 @@ class XMLDBgenerator {
             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);
@@ -233,7 +270,7 @@ class XMLDBgenerator {
 
     /// Add comments if specified and it exists
         if ($this->add_table_comments && $xmldb_table->getComment()) {
-            $comment = $this->getCommentSQL ($xmldb_table);
+            $comment = $this->getCommentSQL($xmldb_table);
         /// Add the COMMENT to results
             $results = array_merge($results, $comment);
         }
@@ -242,7 +279,7 @@ class XMLDBgenerator {
         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 (!$this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) {
                     if ($indextext = $this->getCreateIndexSQL($xmldb_table, $xmldb_index)) {
                         $results = array_merge($results, $indextext);
                     }
@@ -253,14 +290,14 @@ class XMLDBgenerator {
     /// 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 
+            /// 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   
+                /// 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)) {
+                    if (!$this->mdb->get_manager()->index_exists($xmldb_table, $index)) {
                         $createindex = false; //By default
                         switch ($xmldb_key->getType()) {
                             case XMLDB_KEY_UNIQUE:
@@ -304,7 +341,7 @@ class XMLDBgenerator {
      * Given one correct XMLDBIndex, returns the SQL statements
      * needed to create it (in array)
      */
-    function getCreateIndexSQL ($xmldb_table, $xmldb_index) {
+    public function getCreateIndexSQL($xmldb_table, $xmldb_index) {
 
         $unique = '';
         $suffix = 'ix';
@@ -324,7 +361,7 @@ class XMLDBgenerator {
     /**
      * 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)  {
+    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) {
@@ -372,16 +409,15 @@ class XMLDBgenerator {
             }
         }
     /// Calculate the default clause
+        $default_clause = '';
         if (!$skip_default_clause) { //Only if we don't want to skip it
-            $default = $this->getDefaultClause($xmldb_field);
-        } else {
-            $default = '';
+            $default_clause = $this->getDefaultClause($xmldb_field);
         }
     /// Based on default_after_null, set both clauses properly
         if ($this->default_after_null) {
-            $field .= $notnull . $default;
+            $field .= $notnull . $default_clause;
         } else {
-            $field .= $default . $notnull;
+            $field .= $default_clause . $notnull;
         }
     /// The sequence
         if ($xmldb_field->getSequence()) {
@@ -394,7 +430,8 @@ class XMLDBgenerator {
             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;
+                $sql = $this->getEncQuoted($xmldb_field->getName()) . ' ' . $sequencename;
+                return $sql;
             }
         }
         return $field;
@@ -403,7 +440,7 @@ class XMLDBgenerator {
     /**
      * Given one correct XMLDBKey, returns its specs
      */
-    function getKeySQL ($xmldb_table, $xmldb_key) {
+    public function getKeySQL($xmldb_table, $xmldb_key) {
 
         $key = '';
 
@@ -441,14 +478,14 @@ class XMLDBgenerator {
     /**
      * Give one XMLDBField, returns the correct "default value" for the current configuration
      */
-    function getDefaultValue ($xmldb_field) {
+    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 = "'" . addslashes($xmldb_field->getDefault()) . "'";
+                    $default = "'" . $this->addslashes($xmldb_field->getDefault()) . "'";
             } else {
                 $default = $xmldb_field->getDefault();
             }
@@ -462,10 +499,10 @@ class XMLDBgenerator {
             } 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 &&
+                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_clause;
+                    $default = $this->drop_default_value;
                 }
             }
         }
@@ -475,7 +512,7 @@ class XMLDBgenerator {
     /**
      * Given one XMLDBField, returns the correct "default clause" for the current configuration
      */
-    function getDefaultClause ($xmldb_field) {
+    public function getDefaultClause($xmldb_field) {
 
         $defaultvalue = $this->getDefaultValue ($xmldb_field);
 
@@ -490,7 +527,7 @@ class XMLDBgenerator {
      * Given one correct XMLDBTable and the new name, returns the SQL statements
      * to rename it (inside one array)
      */
-    function getRenameTableSQL($xmldb_table, $newname) {
+    public function getRenameTableSQL($xmldb_table, $newname) {
 
         $results = array();  //Array where all the sentences will be stored
 
@@ -501,11 +538,9 @@ class XMLDBgenerator {
 
         $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);
-        }
+    /// Call to getRenameTableExtraSQL() override if needed
+        $extra_sentences = $this->getRenameTableExtraSQL($xmldb_table, $newname);
+        $results = array_merge($results, $extra_sentences);
 
         return $results;
     }
@@ -514,7 +549,7 @@ class XMLDBgenerator {
      * Given one correct XMLDBTable and the new name, returns the SQL statements
      * to drop it (inside one array)
      */
-    function getDropTableSQL($xmldb_table) {
+    public function getDropTableSQL($xmldb_table) {
 
         $results = array();  //Array where all the sentences will be stored
 
@@ -522,11 +557,9 @@ class XMLDBgenerator {
 
         $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);
-        }
+    /// call to getDropTableExtraSQL(), override if needed
+        $extra_sentences = $this->getDropTableExtraSQL($xmldb_table);
+        $results = array_merge($results, $extra_sentences);
 
         return $results;
     }
@@ -534,7 +567,7 @@ class XMLDBgenerator {
     /**
      * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add the field to the table
      */
-    function getAddFieldSQL($xmldb_table, $xmldb_field) {
+    public function getAddFieldSQL($xmldb_table, $xmldb_field) {
 
         $results = array();
 
@@ -542,13 +575,13 @@ class XMLDBgenerator {
         $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);
+        $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());
+            $altertable .= ' AFTER ' . $this->getEncQuoted($xmldb_field->getPrevious());
         }
         $results[] = $altertable;
 
@@ -566,7 +599,7 @@ class XMLDBgenerator {
     /**
      * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop the field from the table
      */
-    function getDropFieldSQL($xmldb_table, $xmldb_field) {
+    public function getDropFieldSQL($xmldb_table, $xmldb_field) {
 
         $results = array();
 
@@ -583,7 +616,7 @@ class XMLDBgenerator {
     /**
      * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to alter the field in the table
      */
-    function getAlterFieldSQL($xmldb_table, $xmldb_field) {
+    public function getAlterFieldSQL($xmldb_table, $xmldb_field) {
 
         $results = array();
 
@@ -596,9 +629,10 @@ class XMLDBgenerator {
 
     /// 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);
+        $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()) {
@@ -614,7 +648,7 @@ class XMLDBgenerator {
     /**
      * 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) {
+    public function getModifyEnumSQL($xmldb_table, $xmldb_field) {
 
         $results = array();
 
@@ -635,7 +669,7 @@ class XMLDBgenerator {
     /**
      * 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) {
+    public function getModifyDefaultSQL($xmldb_table, $xmldb_field) {
 
         $results = array();
 
@@ -657,7 +691,7 @@ class XMLDBgenerator {
      * 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) {
+    public function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
 
         $results = array();  //Array where all the sentences will be stored
 
@@ -678,11 +712,9 @@ class XMLDBgenerator {
 
         $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);
-        }
+    /// Call to getRenameFieldExtraSQL(), override if needed
+        $extra_sentences = $this->getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname);
+        $results = array_merge($results, $extra_sentences);
 
         return $results;
     }
@@ -691,7 +723,7 @@ class XMLDBgenerator {
      * 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) {
+    public function getAddKeySQL($xmldb_table, $xmldb_key) {
 
         $results = array();
 
@@ -702,7 +734,7 @@ class XMLDBgenerator {
             $results[] = $key;
         }
 
-    /// If we aren't creating the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated 
+    /// 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
@@ -713,7 +745,7 @@ class XMLDBgenerator {
             }
             $xmldb_index = new XMLDBIndex('anyname');
             $xmldb_index->setAttributes($indextype, $xmldb_key->getFields());
-            if (!index_exists($xmldb_table, $xmldb_index)) {
+            if (!$this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) {
                 $results = array_merge($results, $this->getAddIndexSQL($xmldb_table, $xmldb_index));
             }
         }
@@ -724,7 +756,7 @@ class XMLDBgenerator {
             $xmldb_key->setType(XMLDB_KEY_UNIQUE);
             $results = array_merge($results, $this->getAddKeySQL($xmldb_table, $xmldb_key));
         }
-        
+
     /// Return results
         return $results;
     }
@@ -732,7 +764,7 @@ class XMLDBgenerator {
     /**
      * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to drop the index from the table
      */
-    function getDropKeySQL($xmldb_table, $xmldb_key) {
+    public function getDropKeySQL($xmldb_table, $xmldb_key) {
 
         $results = array();
 
@@ -741,7 +773,7 @@ class XMLDBgenerator {
     /// 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);
+        $dbkeyname = $this->mdb->get_manager()->find_key_name($xmldb_table, $xmldb_key);
 
     /// Only if such type of key generation is enabled
         $dropkey = false;
@@ -775,13 +807,13 @@ class XMLDBgenerator {
             $results[] = $dropsql;
         }
 
-    /// If we aren't dropping the keys OR if the key is XMLDB_KEY_FOREIGN (not underlying index generated 
+    /// 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)) {
+            if ($this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) {
                 $results = array_merge($results, $this->getDropIndexSQL($xmldb_table, $xmldb_index));
             }
         }
@@ -792,7 +824,7 @@ class XMLDBgenerator {
             $xmldb_key->setType(XMLDB_KEY_UNIQUE);
             $results = array_merge($results, $this->getDropKeySQL($xmldb_table, $xmldb_key));
         }
-        
+
     /// Return results
         return $results;
     }
@@ -802,12 +834,12 @@ class XMLDBgenerator {
      * Experimental! Shouldn't be used at all!
      */
 
-    function getRenameKeySQL($xmldb_table, $xmldb_key, $newname) {
+    public function getRenameKeySQL($xmldb_table, $xmldb_key, $newname) {
 
         $results = array();
 
     /// Get the real key name
-        $dbkeyname = find_key_name($xmldb_table, $xmldb_key);
+        $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) ||
@@ -837,7 +869,7 @@ class XMLDBgenerator {
     /**
      * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to add the index to the table
      */
-    function getAddIndexSQL($xmldb_table, $xmldb_index) {
+    public function getAddIndexSQL($xmldb_table, $xmldb_index) {
 
     /// Just use the CreateIndexSQL function
         return $this->getCreateIndexSQL($xmldb_table, $xmldb_index);
@@ -846,12 +878,12 @@ class XMLDBgenerator {
     /**
      * Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to drop the index from the table
      */
-    function getDropIndexSQL($xmldb_table, $xmldb_index) {
+    public function getDropIndexSQL($xmldb_table, $xmldb_index) {
 
         $results = array();
 
     /// Get the real index name
-        $dbindexname = find_index_name($xmldb_table, $xmldb_index);
+        $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);
@@ -866,25 +898,20 @@ class XMLDBgenerator {
      * 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();
+    /// 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);
-
+        $dbindexname = $this->mdb->get_manager()->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;
+        return array($renamesql);
     }
 
     /**
@@ -894,7 +921,7 @@ class XMLDBgenerator {
      * 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='') {
+    public function getNameForObject($tablename, $fields, $suffix='') {
 
         $name = '';
 
@@ -969,7 +996,7 @@ class XMLDBgenerator {
      * Given any string (or one array), enclose it by the proper quotes
      * if it's a reserved word
      */
-    function getEncQuoted($input) {
+    public function getEncQuoted($input) {
 
         if (is_array($input)) {
             foreach ($input as $key=>$content) {
@@ -1017,7 +1044,7 @@ class XMLDBgenerator {
                          }
                      }
                  /// Values to be sent to DB must be properly escaped
-                     $value = addslashes($value);
+                     $value = $this->addslashes($value);
                  /// Back trimmed quotes
                      $value = "'" . $value . "'";
                  /// Back to the array
@@ -1044,7 +1071,7 @@ class XMLDBgenerator {
      * in the $concat_character setting. If such setting is empty, then
      * MySQL's CONCAT function will be used instead
      */
-    function getConcatSQL($elements) {
+    public function getConcatSQL($elements) {
 
     /// Replace double quoted elements by single quotes
         foreach($elements as $key => $element) {
@@ -1056,30 +1083,14 @@ class XMLDBgenerator {
         }
 
     /// 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;
-        }
+        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
      */
-    function getSequenceFromDB($xmldb_table) {
+    public function getSequenceFromDB($xmldb_table) {
         return false;
     }
 
@@ -1090,8 +1101,8 @@ class XMLDBgenerator {
      * (invoked from getNameForObject()
      * Only some DB have this implemented
      */
-    function isNameInUse($object_name, $type, $table_name) {
-        return false; //For generators not implementing introspecion, 
+    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
     }
 
@@ -1101,123 +1112,141 @@ class XMLDBgenerator {
     /**
      * 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()';
-    }
+    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
      */
-    function getEnumSQL ($xmldb_field) {
-        return 'code for inline enum declaration goes to function getEnumSQL(). Can be disabled with enum_inline_code=false';
+    public function getEnumSQL($xmldb_field) {
+        return '';
     }
 
     /**
      * 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';
+    public function getEnumExtraSQL($xmldb_table, $xmldb_field) {
+        return '';
     }
 
     /**
      * 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;');
+    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
      */
-    function getCreateSequenceSQL ($xmldb_table, $xmldb_field) {
-        return array('Code for extra sequence SQL goes to getCreateSequenceSQL(). Can be disabled with sequence_extra_code=false');
+    public function getCreateSequenceSQL($xmldb_table, $xmldb_field) {
+        return array();
     }
 
     /**
      * 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;');
-    }
+    public abstract function getCommentSQL($xmldb_table);
 
     /**
      * 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;');
+    public function getRenameTableExtraSQL($xmldb_table) {
+        return array();
     }
 
     /**
      * 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;');
+    public function getDropTableExtraSQL($xmldb_table) {
+        return array();
     }
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its enum 
+     * 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()');
-    }
+    public abstract function getDropEnumSQL($xmldb_table, $xmldb_field);
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add its enum 
+     * 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()');
-    }
+    public abstract function getCreateEnumSQL($xmldb_table, $xmldb_field);
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to drop its default 
+     * 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()');
-    }
+    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)
      */
-    function getCheckConstraintsFromDB($xmldb_table, $xmldb_field=null) {
-        return array('Code to fetch check constraints goes to getCheckConstraintsFromDB()');
-    }
+    public abstract function getCheckConstraintsFromDB($xmldb_table, $xmldb_field=null);
 
     /**
-     * Given one XMLDBTable and one XMLDBField, return the SQL statements needded to add its default 
+     * 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()');
-    }
+    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
      */
-    function getReservedWords() {
-    /// Some well-know reserved words
-        $reserved_words = array (
-            'user', 'scale', 'type', 'comment', 'view', 'value', 'table', 'index', 'key', 'sequence', 'trigger'
-        );
-        return $reserved_words;
-    }
+    public static abstract function getReservedWords();
 
     /**
-     * Returns an array of tables to be built without prefix (lowercase)
-     * It's enough to keep updated here this function.
+     * Returns all reserved works in supported databases.
+     * @return array ('word'=>array(databases))
      */
-    function getTablesWithoutPrefix() {
-    /// Some well-known tables to be created without prefix
-        $tables = array (
-            'adodb_logsql'
-        );
-        return $tables;
+    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 7888d608b1c5e4edda837dff591cc263394091b2..1f94e43dda5f9a9dc2084adb6b35a6913f4ae502 100644 (file)
 // 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 @@ function delete_tables_from_xmldb_file($file, $feedback=true ) {
  * @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 @@ function get_db_directories() {
     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;
 
-    $status = true;
+// DEPRECATED - to be removed soon
 
-    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
diff --git a/lib/dml/adodb_moodle_database.php b/lib/dml/adodb_moodle_database.php
new file mode 100644 (file)
index 0000000..a13d5a9
--- /dev/null
@@ -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;
+    }
+
+}
diff --git a/lib/dml/adodb_moodle_recordset.php b/lib/dml/adodb_moodle_recordset.php
new file mode 100644 (file)
index 0000000..e69680e
--- /dev/null
@@ -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;
+    }
+}
diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php
new file mode 100644 (file)
index 0000000..58bab96
--- /dev/null
@@ -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;
+    }
+}
diff --git a/lib/dml/mssql_adodb_moodle_database.php b/lib/dml/mssql_adodb_moodle_database.php
new file mode 100644 (file)
index 0000000..c45eadc
--- /dev/null
@@ -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;
+
+    }
+
+}
diff --git a/lib/dml/mssql_n_adodb_moodle_database.php b/lib/dml/mssql_n_adodb_moodle_database.php
new file mode 100644 (file)
index 0000000..1e296da
--- /dev/null
@@ -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;
+    }
+
+}
diff --git a/lib/dml/mysql_adodb_moodle_database.php b/lib/dml/mysql_adodb_moodle_database.php
new file mode 100644 (file)
index 0000000..7adf87c
--- /dev/null
@@ -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';
+    }
+
+}
diff --git a/lib/dml/mysqli_adodb_moodle_database.php b/lib/dml/mysqli_adodb_moodle_database.php
new file mode 100644 (file)
index 0000000..0880971
--- /dev/null
@@ -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) ';
+    }
+
+}
diff --git a/lib/dml/oci8po_adodb_moodle_database.php b/lib/dml/oci8po_adodb_moodle_database.php
new file mode 100644 (file)
index 0000000..e8d86c1
--- /dev/null
@@ -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;
+}
diff --git a/lib/dml/oci8po_adodb_moodle_recordset.php b/lib/dml/oci8po_adodb_moodle_recordset.php
new file mode 100644 (file)
index 0000000..71a7064
--- /dev/null
@@ -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();
+    }
+}
diff --git a/lib/dml/odbc_mssql_adodb_moodle_database.php b/lib/dml/odbc_mssql_adodb_moodle_database.php
new file mode 100644 (file)
index 0000000..f626331
--- /dev/null
@@ -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;
+    }
+
+}
diff --git a/lib/dml/pdo_moodle_database.php b/lib/dml/pdo_moodle_database.php
new file mode 100644 (file)
index 0000000..6051885
--- /dev/null
@@ -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;
+    }
+
+}
diff --git a/lib/dml/pdo_moodle_recordset.php b/lib/dml/pdo_moodle_recordset.php
new file mode 100644 (file)
index 0000000..6ffb023
--- /dev/null
@@ -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;
+    }
+}
diff --git a/lib/dml/postgres7_adodb_moodle_database.php b/lib/dml/postgres7_adodb_moodle_database.php
new file mode 100644 (file)
index 0000000..c6da6a9
--- /dev/null
@@ -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 842b93759dee473c96a6920a621de9f6d9aa81ce..de0fd8f09cb05f735c79b319b6aacf4bcd5ef226 100644 (file)
 
 /// 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='') {
+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;
 
-    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;
-    }
+    public $meta_type; // type as one character
 
-    $command = '';
-
-    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);
+}
 
-    // 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;
-        }
-    }
+function sql_order_by_text($fieldname, $numchars=32) {
+    global $DB;
+    return $DB->sql_order_by_text($fieldname, $numchars);
+}
 
-    $select = where_clause($field1, $value1, $field2, $value2, $field3, $value3);
 
-    $record = get_record_sql('SELECT '.$fields.' FROM '. $CFG->prefix . $table .' '. $select);
+function sql_concat_join($separator="' '", $elements=array()) {
+    global $DB;
+    return $DB->sql_concat_join($separator, $elements);
+}
 
-    // 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_isempty($tablename, $fieldname, $nullablefield, $textfield) {
+    global $DB;
+    return $DB->sql_isempty($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;
-
-/// 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;
-    }
+function sql_isnotempty($tablename, $fieldname, $nullablefield, $textfield) {
+    global $DB;
+    return $DB->sql_isnotempty($tablename, $fieldname, $nullablefield, $textfield);
+}
 
-    if (!$rs = get_recordset_sql($sql, $limitfrom, $limitnum)) {
-        return false;
-    }
 
-    $recordcount = $rs->RecordCount();
+function begin_sql() {
+    global $DB;
+    return $DB->begin_sql();
+}
 
-    if ($recordcount == 0) {          // Found no records
-        return false;
+function commit_sql() {
+    global $DB;
+    return $DB->commit_sql();
+}
 
-    } 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");
-    }
+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);
-
-    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;
+function delete_records($table, $field1='', $value1='', $field2='', $value2='', $field3='', $value3='') {
+    global $DB;
+
+    $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');
 }
-
-?>
diff --git a/lib/dmllib_todo.php b/lib/dmllib_todo.php
new file mode 100644 (file)
index 0000000..03e0e08
--- /dev/null
@@ -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;
+}
+
+?>
\ No newline at end of file
index 614fe1342cc36927a99e873abdc93c1c660a16c2..71cd733fb46bc5fbacd8ab19c02099442b2e9dd1 100644 (file)
@@ -680,7 +680,7 @@ function environment_check_php($version) {
  * @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 @@ function environment_check_unicode($version) {
         $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_unicode($version) {
  */
 function environment_check_database($version) {
 
-    global $db;
+    global $DB;
 
     $result = new environment_results('database');
 
@@ -779,9 +779,9 @@ function environment_check_database($version) {
     }
 
 /// 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 d50ded7c24dc187a4d292630e9add3a8bead7ef2..9679939f8f66ddc5bc2693bcc71be4f9ef42c2af 100644 (file)
@@ -733,9 +733,9 @@ function send_file($path, $filename, $lifetime=86400 , $filter=0, $pathisstring=
 }
 
 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 get_records_csv($file, $table) {
 }
 
 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 69b0957c0019cc347d4a69ac1f0b3f7e7e0fdce1..b5b10c5204d9524e34a9c5ea57d2967530d07485 100644 (file)
@@ -774,10 +774,12 @@ class grade_item extends grade_object {
      * @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 4e76f35c756e48e9119143e3a8cc1f29e6745d00..d566388a88e1740243153f86bf7d5fa1b0fa02e6 100644 (file)
@@ -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 @@ class grade_lib_wrapper {
     function rs_close(&$rs) {
         return;
     }
-    
+*/    
     function get_coursemodule_from_instance($modulename, $instance, $courseid=0) {
         return get_coursemodule_from_instance($modulename, $instance, $courseid);
     }
index a33ee5e5b7f0e4cf5f22f7b2501f5f11be823b51..7b3d6db12e276b2f5d4831eef08c1caf09f5c1a2 100644 (file)
@@ -23,7 +23,8 @@ define('VISIBLEGROUPS', 2);
  * 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 @@ function groups_group_exists($groupid) {
  * @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 @@ function groups_get_group_name($groupid) {
  * @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 @@ function groups_get_grouping_name($groupingid) {
  * @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 @@ function groups_get_group_by_name($courseid, $name) {
  * @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 @@ function groups_get_grouping_by_name($courseid, $name) {
  * @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 @@ function groups_get_group($groupid) {
  * @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 @@ function groups_get_grouping($groupingid) {
  * 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 @@ function groups_get_all_groups($courseid, $userid=0, $groupingid=0, $fields='g.*
  * @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 @@ function groups_get_user_groups($courseid, $userid=0) {
         }
         $result[$group->groupingid][$group->id] = $group->id;
     }
-    rs_close($rs);
+    $rs->close();
 
     $result['0'] = array_keys($allgroups); // all groups
 
@@ -182,16 +193,16 @@ function groups_get_user_groups($courseid, $userid=0) {
  * 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 @@ function groups_get_all_groupings($courseid) {
  * @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 @@ function groups_is_member($groupid, $userid=null) {
  * @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 @@ function groups_has_membership($cm, $userid=null) {
     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 @@ function groups_has_membership($cm, $userid=null) {
  * 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 @@ function groups_get_members($groupid, $fields='u.*', $sort='lastname ASC') {
  * group or false if no users or an error returned.
  */
 function groups_get_grouping_members($groupingid, $fields='u.*', $sort='lastname ASC') {
-    global $CFG;
-
-    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");
+    global $DB;
+
+    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 @@ function groups_get_course_groupmode($course) {
  * @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 @@ function groups_get_activity_groupmode($cm, $course=null) {
     } 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 d67abb39928d62ba510a2c3ea49d0b5fd52167c5..957eb37fd5d76991529df3acf119a14d63d52921 100644 (file)
@@ -141,11 +141,11 @@ function upgrade_local_db($continueto) {
         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 @@ function upgrade_local_db($continueto) {
             }
         } else {
             if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
-            $db->debug=false;
+                $DB->set_debug(false);
             }
             print_error('Upgrade failed!  See local/version.php');
         }
index 44bc970223b8ca881b917447691b7d14bb8188fd..d7198096b9d80fa2e1116b708b4fd447c858ee2c 100644 (file)
@@ -1432,15 +1432,13 @@ function get_user_timezone($tz = 99) {
 }
 
 /**
- * ?
+ * 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 @@ function get_timezone_record($timezonename) {
         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 @@ function is_internal_auth($auth) {
 /**
  * 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 array_is_nested($array) {
  ***
  **/
 function get_performance_info() {
-    global $CFG, $PERF, $rcache;
+    global $CFG, $PERF;
 
     $info = array();
     $info['html'] = '';         // holds userfriendly HTML representation
@@ -7602,14 +7598,14 @@ function get_performance_info() {
         $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 1dfa338ecbda6296d4f029cc38b7968463e1f973..cb21375440df2b34b4ae1cb9d2a8509769358a7d 100644 (file)
@@ -54,10 +54,15 @@ global $MCACHE;
  */
 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.
  *
@@ -115,81 +120,16 @@ global $HTTPSPAGEREQUIRED;
         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 @@ global $HTTPSPAGEREQUIRED;
     //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 @@ global $HTTPSPAGEREQUIRED;
         $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 @@ global $HTTPSPAGEREQUIRED;
                                              $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 b076a9a8c9881695537eca82c2cf43bb1c6d7cb0..ecbf8d868100c3caf1dec6fa9cdbc0c8be61d536 100644 (file)
@@ -164,148 +164,6 @@ function make_upload_directory($directory, $shownotices=true) {
     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 0c7062ed05f7ec5f06e04ea9c0ad8f846e75d89d..a5cc2d7b6e19c1a33d40050f63d8939144e23a62 100644 (file)
@@ -1375,7 +1375,7 @@ function format_text_menu() {
  */
 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 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
             }
         }
 
-        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 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
 
         $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 @@ function current_theme() {
  * @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 @@ function current_category_theme($categoryid=0) {
     }
 
 /// 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 @@ function theme_setup($theme = '', $params=NULL) {
  * @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 @@ function user_login_string($course=NULL, $user=NULL) {
     }
 
     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 @@ function user_login_string($course=NULL, $user=NULL) {
 
         $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 @@ function user_login_string($course=NULL, $user=NULL) {
                       " (<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 @@ function print_navigation ($navigation, $separator=0, $return=false) {
  *      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 @@ function build_navigation($extranavlinks, $cm = null) {
             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 @@ function build_navigation($extranavlinks, $cm = null) {
             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 @@ function print_file_picture($path, $courseid=0, $height='', $width='', $link='',
  * @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 @@ function print_user_picture($user, $courseid, $picture=NULL, $size=0, $return=fa
         }
     }
     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 update_categories_search_button($search,$page,$perpage) {
  */
 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 @@ function navmenu($course, $cm=NULL, $targetwindow='self') {
     $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 @@ function redirect($url, $message='', $delay=-1) {
  * @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 @@ function notify($message, $style='notifyproblem', $align='center', $return=false
     $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 ;
     }
similarity index 89%
rename from lib/xmldb/classes/XMLDBStatement.class.php
rename to lib/xmldb/XMLDBStatement.class.php
index fb2bfb8c39a64ca6b767dfa2afa3a8d9220938b9..90cfcaac8922c48ea7b8c72b703a510a314627ec 100644 (file)
@@ -369,55 +369,6 @@ class XMLDBStatement extends XMLDBObject {
 
         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;
-    }
-
 }
 
 ?>
similarity index 96%
rename from lib/xmldb/classes/XMLDBStructure.class.php
rename to lib/xmldb/XMLDBStructure.class.php
index 45064b26bba6a93524dbd68760b9e2d6424ef6a5..526a917299c97e68bc74242fdd929d5655535c8a 100644 (file)
@@ -714,28 +714,6 @@ class XMLDBStructure extends XMLDBObject {
             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;
-    }
 }
 
 ?>
similarity index 72%
rename from lib/xmldb/classes/XMLDBTable.class.php
rename to lib/xmldb/XMLDBTable.class.php
index e2594d64f6473f80da76804a36f33daac6475828..7ad0d2a925e2dde510e7d5062efef694d09abf5d 100644 (file)
@@ -791,290 +791,6 @@ class XMLDBTable extends XMLDBObject {
             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);
-    }
 }
 
 ?>
diff --git a/lib/xmldb/classes/generators/mssql_n/mssql_n.class.php b/lib/xmldb/classes/generators/mssql_n/mssql_n.class.php
deleted file mode 100644 (file)
index a71cc4b..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php // $Id$
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// 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();
-    }
-}
-
-?>
diff --git a/lib/xmldb/classes/generators/mysqli/mysqli.class.php b/lib/xmldb/classes/generators/mysqli/mysqli.class.php
deleted file mode 100644 (file)
index 186ee11..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php // $Id$
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// 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();
-    }
-}
-
-?>
diff --git a/lib/xmldb/classes/generators/odbc_mssql/odbc_mssql.class.php b/lib/xmldb/classes/generators/odbc_mssql/odbc_mssql.class.php
deleted file mode 100644 (file)
index 4ba3e7c..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php // $Id$
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// 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 6055bc5fa59159ca5f16139c609c4bd090644ac8..3af92c8b775779181bde78a5ea2143f7a8849391 100644 (file)
 
 function xmldb_assignment_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
 
     $result = true;
 
-    if ($result && $oldversion < 2007091900) { /// MDL-11268
-
-    /// Changing nullability of field data1 on table assignment_submissions to null
-        $table = new XMLDBTable('assignment_submissions');
-        $field = new XMLDBField('data1');
-        $field->setAttributes(XMLDB_TYPE_TEXT, 'small', null, null, null, null, null, null, 'numfiles');
-
-    /// Launch change of nullability for field data1
-        $result = $result && change_field_notnull($table, $field);
-
-    /// Changing nullability of field data2 on table assignment_submissions to null
-        $field = new XMLDBField('data2');
-        $field->setAttributes(XMLDB_TYPE_TEXT, 'small', null, null, null, null, null, null, 'data1');
-
-    /// Launch change of nullability for field data2
-        $result = $result && change_field_notnull($table, $field);
-    }
-
-    if ($result && $oldversion < 2007091902) {
-        // add draft tracking default to existing upload assignments
-        $sql = "UPDATE {$CFG->prefix}assignment SET var4=1 WHERE assignmenttype='upload'";
-        $result = execute_sql($sql);
-    }
+//===== 1.9.0 upgrade line ======//
 
     if ($result && $oldversion < 2007101511) {
         notify('Processing assignment grades, this may take a while if there are many assignments...', 'notifysuccess');
         // 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 ab5fa4215b00811b144fc0d8094ed50e4540bcb9..8eb40b4f98f8ea730225fc4182ecb86d00bc33a2 100644 (file)
@@ -401,31 +401,25 @@ function chat_get_users($chatid, $groupid=0, $groupingid=0) {
 }
 
 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;
-    }
+    $sql = "SELECT *
+              FROM {chat_messages}
+             WHERE chatid = ?
+                   $groupselect
+          ORDER BY timestamp DESC";
+    $params[] = $chatid;
 
-    $result = rs_fetch_record($rs);
-    
-    rs_close($rs);
-
-    return $result;
+    return $DB->get_record_sql($sql, $params, true);
 }
 
 
index 3f752b34c91251952734c1e1ee519626b7caddbb..32ae30e182d1233e28158e0a42d5f525fbe7ffc8 100644 (file)
@@ -97,8 +97,9 @@ class mod_choice_mod_form extends moodleform_mod {
     }
 
     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 1b3d222f3c88606e2488f0f8348bd57836efc796..082293f592d1dac5bec81816ba388a68d1e1e0c3 100644 (file)
 
 function xmldb_data_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
 
-    $result = true;
-
-/// And upgrade begins here. For each one, you'll need one
-/// block of code similar to the next one. Please, delete
-/// this comment lines once this file start handling proper
-/// upgrade code.
-
-/// if ($result && $oldversion < YYYYMMDD00) { //New version in version.php
-///     $result = result of "/lib/ddllib.php" function calls
-/// }
-
-    if ($result && $oldversion < 2006121300) {
-
-    /// Define field format to be added to data_comments
-        $table = new XMLDBTable('data_comments');
-        $field = new XMLDBField('format');
-        $field->setAttributes(XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'content');
-
-    /// Launch add field format
-        $result = $result && add_field($table, $field);
-
-    }
-    
-    if ($result && $oldversion < 2007022600) {
-    /// Define field asearchtemplate to be added to data
-        $table = new XMLDBTable('data');
-        $field = new XMLDBField('asearchtemplate');
-        $field->setAttributes(XMLDB_TYPE_TEXT, 'small', null, null, null, null, null, null, 'jstemplate');
-
-    /// Launch add field asearchtemplate
-        $result = $result && add_field($table, $field);
-    }
-
-
-    if ($result && $oldversion < 2007072200) {
-        require_once($CFG->dirroot.'/mod/data/lib.php');
-        // too much debug output
-        $db->debug = false;
-        data_update_grades();
-        $db->debug = true;
-    }  
+    $dbman = $DB->get_manager();
 
-    if ($result && $oldversion < 2007081400) {
-
-    /// Define field notification to be added to data
-        $table = new XMLDBTable('data');
-        $field = new XMLDBField('notification');
-        $field->setAttributes(XMLDB_TYPE_INTEGER, '10', null, null, null, null, null, null, 'editany');
-
-    /// Launch add field notification
-        $result = $result && add_field($table, $field);
-    }
-
-    if ($result && $oldversion < 2007081402) {
-
-    /// Define index type-dataid (not unique) to be added to data_fields
-        $table = new XMLDBTable('data_fields');
-        $index = new XMLDBIndex('type-dataid');
-        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('type', 'dataid'));
-
-    /// Launch add index type-dataid
-        if (!index_exists($table, $index)) {
-            $result = $result && add_index($table, $index);
-        }
+    $result = true;
 
-    /// Define index course (not unique) to be added to data
-        $table = new XMLDBTable('data');
-        $index = new XMLDBIndex('course');
-        $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('course'));
-
-    /// Launch add index course
-        if (!index_exists($table, $index)) {
-            $result = $result && add_index($table, $index);
-        }
-    }
+//===== 1.9.0 upgrade line ======//
 
     if ($result && $oldversion < 2007101512) {
     /// Launch add field asearchtemplate again if does not exists yet - reported on several sites
@@ -104,8 +34,8 @@ function xmldb_data_upgrade($oldversion=0) {
         $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);
         }
     }
 
@@ -113,14 +43,15 @@ function xmldb_data_upgrade($oldversion=0) {
         // 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 21cf5c4a66c3a264473e798757f8aca62f81274e..855998c9cb5f6181d037efe86cf947892c05417d 100755 (executable)
         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 24c27a89f1c51e02f46bddfd2bb0a722399147a8..08f9883677209c41c3349e86c05671909a47a7f5 100644 (file)
@@ -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 @@ function xmldb_feedback_upgrade($oldversion=0) {
         $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 @@ function xmldb_feedback_upgrade($oldversion=0) {
         $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 @@ function xmldb_feedback_upgrade($oldversion=0) {
         $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 @@ function xmldb_feedback_upgrade($oldversion=0) {
 
         $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 @@ function xmldb_feedback_upgrade($oldversion=0) {
         $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 @@ function xmldb_feedback_upgrade($oldversion=0) {
         $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 @@ function xmldb_feedback_upgrade($oldversion=0) {
         $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 9ca8ec2e3a1f66ab9b9c29c8381f9e9961f941ba..9e774d625f8b05ae0c0f6462eaf4987853ce9405 100644 (file)
@@ -32,25 +32,16 @@ function xmldb_forum_upgrade($oldversion=0) {
 ///     $result = result of "/lib/ddllib.php" function calls
 /// }
 
-    if ($result && $oldversion < 2007101000) {
-
-    /// Define field timemodified to be added to forum_queue
-        $table = new XMLDBTable('forum_queue');
-        $field = new XMLDBField('timemodified');
-        $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'postid');
-
-    /// Launch add field timemodified
-        $result = $result && add_field($table, $field);
-    }
+//===== 1.9.0 upgrade line ======//
 
     if ($result and $oldversion < 2007101511) {
         notify('Processing forum grades, this may take a while if there are many forums...', 'notifysuccess');
         //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) {
@@ -71,12 +62,12 @@ function xmldb_forum_upgrade($oldversion=0) {
                  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 3f304b8e013479fd4d1159acb9d159d26223394b..69f535651b1c6530d956914e0ffa7caffab401d2 100644 (file)
@@ -157,7 +157,7 @@ if ($mform->is_cancelled()){
 
         $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 @@ if ($mform->is_cancelled()){
             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 b9f357eaeee5a8146e2cfac849b3de6bb93a5781..426b30eed132edbe4e7d85aa09cae1cf046dc662 100644 (file)
@@ -5,7 +5,7 @@ class mod_glossary_entry_form extends moodleform {
 
     function definition() {
 
-        global $CFG, $COURSE;
+        global $CFG, $COURSE, $DB;
         $mform    =& $this->_form;
 
         $glossary =& $this->_customdata['glossary'];
@@ -29,7 +29,7 @@ class mod_glossary_entry_form extends moodleform {
         $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 b64e8bc0bf69b09d8e2d1790b82e9bb083eb756a..5cd04241fd9caeb6919a1197c35cdc3db6c2b7a1 100644 (file)
@@ -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 {
 
     // 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
             $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 92dd6f81ff46cfdbc7ce4b377135247d1e394220..ec2d495ba22037632343d047ae1f69d9a573a354 100644 (file)
@@ -4,10 +4,12 @@
 
 function xmldb_hotpot_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
 
     $result = true;
 
+//===== 1.9.0 upgrade line ======//
+
     // update hotpot grades from sites earlier than Moodle 1.9, 27th March 2008
     if ($result && $oldversion < 2007101511) {
 
@@ -15,14 +17,13 @@ function xmldb_hotpot_upgrade($oldversion=0) {
         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 f5722376872974da0c333d8a367e4cc02838560c..1ab3df6008f27322d98e9727be92a2d21cb74497 100644 (file)
                             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 a4b2a63c4293aeed299465b441cfebadecf9e128..925b7dc72f7eb26e59365a11782be90546c042d3 100644 (file)
@@ -2191,7 +2191,7 @@ function hotpot_add_attempt_details(&$attempt) {
     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 @@ function hotpot_add_response(&$attempt, &$question, &$response) {
         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 @@ function hotpot_add_response(&$attempt, &$question, &$response) {
 
             // 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 @@ function hotpot_string_id($str) {
 
             // 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 9dea6f8ae54d296242a95b9e4a78c90200e35110..8a0a344bb9fb5b48c99a5124727adf13653e6efa 100644 (file)
@@ -298,8 +298,8 @@ function hotpot_restore_record(&$restore, $status, &$xml, $table, $foreign_keys,
     // 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 b5d8e405f109d010c50794764aa0f446ceecacc0..3c9ddf3271addcda541ba669404ec251575b765a 100644 (file)
 
                 $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 432292e637c3ed807a7bf7c857ca2cc1c86aee2b..7c8366f3aca738cc31ead09df516aa2b6ef64927 100644 (file)
 
 function xmldb_lesson_upgrade($oldversion=0) {
 
-    global $CFG, $THEME, $db;
+    global $CFG, $THEME, $DB;
 
-    $result = true;
-
-    if ($result && $oldversion < 2006091802) {
-
-    /// Changing nullability of field response on table lesson_answers to null
-        $table = new XMLDBTable('lesson_answers');
-        $field = new XMLDBField('response');
-        $field->setAttributes(XMLDB_TYPE_TEXT, 'small', null, null, null, null, null, null, 'answer');
-
-    /// Launch change of nullability for field response
-        $result = $result && change_field_notnull($table, $field);
-    }
-
-    if ($result && $oldversion < 2006091803) {
-
-    /// Changing nullability of field useranswer on table lesson_attempts to null
-        $table = new XMLDBTable('lesson_attempts');
-        $field = new XMLDBField('useranswer');
-        $field->setAttributes(XMLDB_TYPE_TEXT, 'small', null, null, null, null, null, null, 'correct');
+    $dbman = $DB->get_manager();
 
-    /// Launch change of nullability for field useranswer
-        $result = $result && change_field_notnull($table, $field);
-    }
-
-    if ($result && $oldversion < 2007020201) {
-
-    /// Changing nullability of field answer on table lesson_answers to null
-        $table = new XMLDBTable('lesson_answers');
-        $field = new XMLDBField('answer');
-        $field->setAttributes(XMLDB_TYPE_TEXT, 'small', null, null, null, null, null, null, 'timemodified');
-
-    /// Launch change of nullability for field answer
-        $result = $result && change_field_notnull($table, $field);
-    }
+    $result = true;
 
-    if ($result && $oldversion < 2007072200) {
-        require_once($CFG->dirroot.'/mod/lesson/lib.php');
-        // too much debug output
-        $db->debug = false;
-        lesson_update_grades();
-        $db->debug = true;
-    }
+//===== 1.9.0 upgrade line ======//
 
     if ($result && $oldversion < 2007072201) {
 
@@ -71,11 +34,11 @@ function xmldb_lesson_upgrade($oldversion=0) {
         $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 89a7c5de5a83ae9e0533437a87b005e8f8221373..f002ba84befe63ea5e567c6e19844005e9b52524 100644 (file)
@@ -241,11 +241,11 @@ class quiz_report extends quiz_default_report {
         $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 @@ class quiz_report extends quiz_default_report {
         }
 
         // 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 @@ class quiz_report extends quiz_default_report {
         $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 @@ class quiz_report extends quiz_default_report {
         // 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 d54a4cb186f09355b2932270700b69c699563a5a..888729fe3eebe5b6dfe945d0196eb9a87c481681 100644 (file)
@@ -306,7 +306,7 @@ class quiz_report extends quiz_default_report {
         }
 
         // 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 @@ class quiz_report extends quiz_default_report {
 
         
 
-        $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 573f1256bf4b99f73bfd19f1f97c3a04b4aa4e5d..3962270b2781fec6c31b58b51a2ccc97d4df4873 100644 (file)
@@ -5,7 +5,7 @@ class mod_survey_mod_form extends moodleform_mod {
 
     function definition() {
 
-        global $CFG;
+        global $CFG, $DB;
         $mform =& $this->_form;
 
         $strrequired = get_string('required');
@@ -17,7 +17,7 @@ class mod_survey_mod_form extends moodleform_mod {
         $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 17b1979a230ed4654f29fa569583d5bacb56eb86..bba6058a630368c528b6d46d0531b85a9f2f8546 100755 (executable)
@@ -19,9 +19,9 @@ function ewiki_page_orphanedpages($id, $data, $action) {
    $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 737c2da4748e5af47cc2868b85a69c88d9658792..b107ec1a5acb3b55b70d0a56c385175ac04d31d0 100644 (file)
@@ -37,7 +37,7 @@ class IndexInfo {
             $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 @@ class IndexInfo {
         $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 @@ class IndexInfo {
             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 @@ class IndexDBControl {
     * @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 {