/// 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);
}
/// 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;
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 !!!");
}
<?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();
+ }
?>
admin_externalpage_print_header();
if (!extension_loaded('openssl')) {
- print_error('requiresopenssl', 'mnet', '', NULL, true);
+ print_error('requiresopenssl', 'mnet');
}
$sitecontext = get_context_instance(CONTEXT_SYSTEM);
$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]);
}
// 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) {
// 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)) {
// 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');
}
-if (!$tables = $db->Metatables() ) { // No tables yet at all.
+if (!$tables = $DB->get_tables() ) { // No tables yet at all.
print_error('notables', 'debug');
}
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 />';
}
echo '.';
}
$i++;
- $rs->MoveNext();
if (empty($text) or is_numeric($text)) {
continue; // nothing to do
}
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();
}
}
}
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');
$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);
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();
$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');
$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;
$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>';
}
/// 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()) {
/// 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;
}
/// 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;
$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>';
/// 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 {
$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();
}
/// 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()) {
}
/// 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()) {
/// 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;
}
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
$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() . ', ' .
$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 />';
}
}
$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');
}
/// 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()) {
/// 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();
}
/// 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());
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>';
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>';
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)
/// 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" />';
/// 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" />';
$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');
$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 .= ' <a href="index.php?action=view_reserved_words"><span class="error">' . $this->str['reserved'] . '</span></a>';
}
/// The readable info
$this->does_generate = ACTION_GENERATE_HTML;
/// These are always here
- global $CFG, $XMLDB;
+ global $CFG, $XMLDB, $DB;
/// Do the job, setting $result as needed
/// The new table button
$b .= ' <a href="index.php?action=new_table&postaction=edit_table&table=changeme&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 .= ' <a href="index.php?action=new_table_from_mysql&dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '">[' . $this->str['newtablefrommysql'] . ']</a>';
} else {
$b .= ' [' . $this->str['newtablefrommysql'] . ']';
$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">';
$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 .= ' <a href="index.php?action=view_reserved_words"><span class="error">' . $this->str['reserved'] . '</span></a>';
}
$b .= '</td>';
$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 {
$this->does_generate = ACTION_GENERATE_HTML;
/// These are always here
- global $CFG, $XMLDB, $SESSION;
+ global $CFG, $XMLDB, $SESSION, $DB;
/// Get lastused
$o = '';
/// The check defaults button
$b .= ' <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 .= ' <a href="index.php?action=check_bigints">[' . $this->str['checkbigints'] . ']</a>';
}
$b .= '</p>';
$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
/// 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),
$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
/// 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;
$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
}
}
/// 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) {
$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();
/// 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.
/// 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;
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;
}
$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;
}
$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) {
$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;
}
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;
}
$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;
}
$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;
}
/// 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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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 {
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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;
}
$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
$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
$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;
}
/// 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;
}
$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;
}
$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;
}
$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;
}
/// 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;
}
}
/// 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
$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;
}
$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) {
$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;
}
$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;
}
$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
$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]) . ')';
}
}
}
$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>';
$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
}
/// 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&dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '">[' . $this->str['back'] . ']</a>';
$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&dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '&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";
/**
* 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
$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
/// 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">';
$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&table=' . $tableparam . '&dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '&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";
/// 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
/// 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':
// 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)
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";
/// 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)) {
function get_content() {
- global $CFG, $USER, $SITE, $COURSE;
+ global $CFG, $USER, $SITE, $COURSE, $DB;
if ($this->content !== NULL) {
return $this->content;
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);
$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();
}
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);
class course_edit_form extends moodleform {
function definition() {
- global $USER, $CFG;
+ global $USER, $CFG, $DB;
$mform =& $this->_form;
$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,
* @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";
* 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)) {
$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);
function xmldb_enrol_authorize_upgrade($oldversion=0) {
- global $CFG, $THEME, $db;
+ global $CFG, $THEME, $DB;
$result = true;
}
// 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');
}
}
}
//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 );
// 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'
}
echo "<td>\n";
-// NO GROUPINGS YET!
echo '<p><label for="groups"><span id="groupslabel">'.get_string('groups').':</span><span id="thegrouping"> </span></label></p>'."\n";
if (ajaxenabled()) {
$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";
$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();
}
// 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;
// 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
}
/// 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) {
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
$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();
$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;
// 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();
*/
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
//
$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') {
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();
}
}
}
} 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();
}
}
*/
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;
//
$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;
* @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)) {
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
* @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
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;
* @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;
}
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).
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);
*/
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');
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
// - 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) .')';
}
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;
}
*/
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)
// 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
$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])) {
}
}
unset($ra);
- rs_close($rs);
+ $rs->close();
}
// Walk up the tree to grab all the roledefs
// 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();
}
}
$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;
}
*/
function load_subcontext($userid, $context, &$accessdata) {
- global $CFG;
-
-
+ global $CFG, $DB;
/* Get the additional RAs and relevant rolecaps
* - role assignments - with role_caps
// 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
$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!');
}
*/
function get_role_access_bycontext($roleid, $context, $accessdata=NULL) {
- global $CFG;
+ global $CFG, $DB;
/* Get the relevant rolecaps into rdef
* - relevant role caps
// 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;
}
*
*/
function reload_all_capabilities() {
- global $USER,$CFG;
+ global $USER, $DB;
// error_log("reloading");
// copy switchroles
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
*/
function load_temp_role($context, $roleid, $accessdata) {
- global $CFG;
+ global $CFG, $DB;
//
// Load rdefs for the role in -
$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
/**
* 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
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);
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);
- }
- }
}
/**
* @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');
}
$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;
}
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);
}
* @return success
*/
function delete_role($roleid) {
- global $CFG;
+ global $CFG, $DB;
$success = true;
// mdl 10149, check if this is the last active admin role
$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;
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;
}
*/
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;
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);
}
}
* @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;
}
*/
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).')';
$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 = '';
}
$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);
}
* @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
/// 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));
}
$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
$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
/// 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);
}
/**
* 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');
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
/// 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) {
$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) {
$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
/**
* 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!');
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) {
$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) {
$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
$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)) {
* @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;
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
}
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>';
}
function create_admin_user($user_input=NULL) {
- global $CFG, $USER;
+ global $CFG, $USER, $DB;
if (empty($CFG->rolesactive)) { // No admin user yet.
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)');
}
}
function write_setting($data) {
+ global $DB;
if (!in_array($data, array_keys($this->choices))) {
return get_string('errorsetting', 'admin');
}
$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'));
}
}
}
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'));
}
}
}
function write_setting($data) {
+ global $DB;
$data = trim($data);
$validated = $this->validate($data);
if ($validated !== true) {
$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'));
}
}
}
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='') {
}
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);
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);
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;
}
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);
}
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) {
}
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) {
* @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);
}
// 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
/**
* 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);
}
}
* distribution or not.
*/
function print_plugin_tables() {
+ global $DB;
$plugins_standard = array();
$plugins_standard['mod'] = array('assignment',
'chat',
'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;
/// 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
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)) {
$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) {
'/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
//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();
$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) {
$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
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
/// 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)) {
// 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;
}
$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');
}
}
*/
function user_accesstime_log($courseid=0) {
- global $USER, $CFG, $PERF, $db;
+ global $USER, $CFG, $DB;
if (!isloggedin() or !empty($USER->realuser)) {
// no access tracking
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
}
}
/// 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
}
}
}
<?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"/>
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 ///
////////////////////////////////////////
$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');
$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);
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);
}
$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)
$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;
}
*/
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) {
break;
}
}
- $db->debug = true;
}
?>
--- /dev/null
+<?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);
+ }
+}
+
+?>
// //
///////////////////////////////////////////////////////////////////////////
+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
/**
* 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()) . '))';
* 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;
* 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
/**
* 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();
/**
* 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();
/**
* 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;
$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;
}
/**
* 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 {
}
/**
- * 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
* (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)
}
/**
- * 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();
$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();
/// 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;
}
* 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);
* 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();
* 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':
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;
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 (
// //
///////////////////////////////////////////////////////////////////////////
+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!
}
/**
- * 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);
* 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);
/// 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);
/**
* Given one XMLDB Field, return its enum SQL
*/
- function getEnumSQL ($xmldb_field) {
+ public function getEnumSQL($xmldb_field) {
return 'enum(' . implode(', ', $xmldb_field->getEnumValues()) . ')';
}
* Returns the code (in array) needed to add one comment to the table
*/
function getCommentSQL ($xmldb_table) {
-
$comment = '';
if ($xmldb_table->getComment()) {
$comment .= 'ALTER TABLE ' . $this->getTableName($xmldb_table);
- $comment .= " COMMENT='" . addslashes(substr($xmldb_table->getComment(), 0, 60)) . "'";
+ $comment .= " COMMENT='" . $this->addslashes(substr($xmldb_table->getComment(), 0, 60)) . "'";
}
return array($comment);
}
* 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
$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;
}
/**
* 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;
}
}
/**
* 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 (
// //
///////////////////////////////////////////////////////////////////////////
+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
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()) . '))';
/**
* 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();
/**
* 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');
* 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);
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);
}
/**
* 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();
/**
* 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);
}
/**
* 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();
* - 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;
$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
$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) ||
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;
+ }
}
}
}
/**
- * 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
* 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();
* 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);
* 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);
* 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;
}
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;
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 (
// //
///////////////////////////////////////////////////////////////////////////
+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
/**
* 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()) . '))';
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);
}
/**
* 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();
* 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;
/// 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;
}
}
* 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
$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) ||
}
/// 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
$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
}
/// 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
}
}
- /// 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();
}
/**
- * 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)
}
/**
- * 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);
* 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();
/**
* 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
* 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;
}
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;
/**
* 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 (
// 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;
}
/**
* @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);
}
* 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
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);
/// 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);
}
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);
}
/// 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:
* 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';
/**
* 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) {
}
}
/// 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()) {
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;
/**
* Given one correct XMLDBKey, returns its specs
*/
- function getKeySQL ($xmldb_table, $xmldb_key) {
+ public function getKeySQL($xmldb_table, $xmldb_key) {
$key = '';
/**
* 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();
}
} 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;
}
}
}
/**
* 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);
* 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
$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;
}
* 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
$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;
}
/**
* 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();
$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;
/**
* 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();
/**
* 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();
/// 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()) {
/**
* 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();
/**
* 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();
* 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
$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;
}
* 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();
$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
}
$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));
}
}
$xmldb_key->setType(XMLDB_KEY_UNIQUE);
$results = array_merge($results, $this->getAddKeySQL($xmldb_table, $xmldb_key));
}
-
+
/// Return results
return $results;
}
/**
* Given one XMLDBTable and one XMLDBIndex, return the SQL statements needded to drop the index from the table
*/
- function getDropKeySQL($xmldb_table, $xmldb_key) {
+ public function getDropKeySQL($xmldb_table, $xmldb_key) {
$results = array();
/// 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;
$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));
}
}
$xmldb_key->setType(XMLDB_KEY_UNIQUE);
$results = array_merge($results, $this->getDropKeySQL($xmldb_table, $xmldb_key));
}
-
+
/// Return results
return $results;
}
* 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) ||
/**
* 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);
/**
* 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);
* 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);
}
/**
* 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 = '';
* 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) {
}
}
/// 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
* 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) {
}
/// 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;
}
* (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
}
/**
* 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;
}
}
// 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
* @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);
}
}
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
--- /dev/null
+<?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;
+ }
+
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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;
+
+ }
+
+}
--- /dev/null
+<?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;
+ }
+
+}
--- /dev/null
+<?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';
+ }
+
+}
--- /dev/null
+<?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) ';
+ }
+
+}
--- /dev/null
+<?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;
+}
--- /dev/null
+<?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();
+ }
+}
--- /dev/null
+<?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;
+ }
+
+}
--- /dev/null
+<?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;
+ }
+
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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;
+ }
+}
/// 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');
}
-
-?>
--- /dev/null
+<?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
* @return object results encapsulated in one environment_result object
*/
function environment_check_unicode($version) {
- global $db;
+ global $db, $DB;
$result = new environment_results('unicode');
$level = get_level($data['#']['UNICODE']['0']);
}
- if (!$unicodedb = setup_is_unicodedb()) {
+ if (!$unicodedb = $DB->setup_is_unicodedb()) {
$result->setStatus(false);
} else {
$result->setStatus(true);
*/
function environment_check_database($version) {
- global $db;
+ global $DB;
$result = new environment_results('database');
}
/// 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];
}
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;
}
}
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;
}
* @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);
}
/**
///////////////////////////////////////////////////////////////////////////
class grade_lib_wrapper {
+/*
function get_records_sql($sql, $limitfrom='', $limitnum='') {
return get_records_sql($sql, $limitfrom, $limitnum);
}
function rs_close(&$rs) {
return;
}
-
+*/
function get_coursemodule_from_instance($modulename, $instance, $courseid=0) {
return get_coursemodule_from_instance($modulename, $instance, $courseid);
}
* occurred.
*/
function groups_group_exists($groupid) {
- return record_exists('groups', 'id', $groupid);
+ global $DB;
+ return $DB->record_exists('groups', array('id'=>$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));
}
/**
* @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));
}
/**
* @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;
* @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;
* @return group object
*/
function groups_get_group($groupid) {
- return get_record('groups', 'id', $groupid);
+ global $DB;
+ return $DB->get_record('groups', array('id'=>$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));
}
/**
* 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);
}
/**
* @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;
}
$result[$group->groupingid][$group->id] = $group->id;
}
- rs_close($rs);
+ $rs->close();
$result['0'] = array_keys($allgroups); // all groups
* 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));
}
* @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));
}
/**
* @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();
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];
}
* 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));
}
* 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));
}
/**
* @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) {
} 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');
}
}
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');
}
} else {
if (!defined('CLI_UPGRADE') || !CLI_UPGRADE ) {
- $db->debug=false;
+ $DB->set_debug(false);
}
print_error('Upgrade failed! See local/version.php');
}
}
/**
- * ?
+ * 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) {
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);
}
/**
/**
* 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;
}
***
**/
function get_performance_info() {
- global $CFG, $PERF, $rcache;
+ global $CFG, $PERF;
$info = array();
$info['html'] = ''; // holds userfriendly HTML representation
$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;
}
*/
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.
*
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)
//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;
$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
$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);
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;
*/
function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL) {
- global $CFG, $COURSE;
+ global $CFG, $COURSE, $DB;
static $croncache = array();
}
}
- 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) {
$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
* @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)) {
}
/// 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)) {
* @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;
}
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&return=1&sesskey=".sesskey()."\">$fullname</a>] ";
$fullname = fullname($user, true);
$username = "<a $CFG->frametarget href=\"$CFG->wwwroot/user/view.php?id=$user->id&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') {
" (<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.
* navigation strings.
*/
function build_navigation($extranavlinks, $cm = null) {
- global $CFG, $COURSE;
+ global $CFG, $COURSE, $DB;
if (is_string($extranavlinks)) {
if ($extranavlinks == '') {
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');
}
}
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');
}
}
* @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...
}
}
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) {
*/
function navmenu($course, $cm=NULL, $targetwindow='self') {
- global $CFG, $THEME, $USER;
+ global $CFG, $THEME, $USER, $DB;
if (empty($THEME->navmenuwidth)) {
$width = 50;
$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);
* @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
$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 ;
}
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;
- }
-
}
?>
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;
- }
}
?>
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);
- }
}
?>
+++ /dev/null
-<?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();
- }
-}
-
-?>
+++ /dev/null
-<?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();
- }
-}
-
-?>
+++ /dev/null
-<?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();
- }
-}
-
-?>
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;
}
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);
}
}
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);
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
$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);
}
}
// 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;
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) {
function xmldb_feedback_upgrade($oldversion=0) {
- global $CFG, $THEME, $db;
+ global $CFG, $THEME, $DB;
+
+ $dbman = $DB->get_manager();
$result = true;
$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
$key->setAttributes(XMLDB_KEY_FOREIGN, array('item'), 'feedback_item', 'id');
$table->addKey($key);
- $result = $result && create_table($table);
+ $result = $result && $dbman->create_table($table);
////////////////////////////////////////////////////////////
}
$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);
////////////////////////////////////////////////////////////
}
$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);
}
}
$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) {
$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) {
$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;
}
/// $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) {
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);
}
}
$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);
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);
function definition() {
- global $CFG, $COURSE;
+ global $CFG, $COURSE, $DB;
$mform =& $this->_form;
$glossary =& $this->_customdata['glossary'];
$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'));
// 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");
$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
$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);
}
}
}
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) {
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;
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++;
hotpot_add_response($attempt, $question, $response);
}
function hotpot_add_response(&$attempt, &$question, &$response) {
- global $db, $next_url;
+ global $DB, $next_url;
$loopcount = 1;
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);
}
}
// 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
// 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());
}
}
}
// 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
$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();
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) {
$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');
}
}
$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
}
// 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
$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.') ';
// 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);
}
// 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 ';
- $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
function definition() {
- global $CFG;
+ global $CFG, $DB;
$mform =& $this->_form;
$strrequired = get_string('required');
$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!');
}
$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"];
$time; //date index was generated
public function __construct($path = SEARCH_INDEX_PATH) {
- global $CFG, $db;
+ global $CFG, $DB;
$this->path = $path;
$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();
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 {
* @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 {