Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/dml/simpletest/testdml.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00025 defined('MOODLE_INTERNAL') || die();
00026 
00027 class dml_test extends UnitTestCase {
00028     private $tables = array();
00030     private $tdb;
00031     private $data;
00032     public  static $includecoverage = array('lib/dml');
00033     public  static $excludecoverage = array('lib/dml/simpletest');
00034 
00035     protected $olddebug;
00036     protected $olddisplay;
00037 
00038     function setUp() {
00039         global $DB, $UNITTEST;
00040 
00041         if (isset($UNITTEST->func_test_db)) {
00042             $this->tdb = $UNITTEST->func_test_db;
00043         } else {
00044             $this->tdb = $DB;
00045         }
00046     }
00047 
00048     function tearDown() {
00049         $dbman = $this->tdb->get_manager();
00050 
00051         foreach ($this->tables as $tablename) {
00052             if ($dbman->table_exists($tablename)) {
00053                 $table = new xmldb_table($tablename);
00054                 $dbman->drop_table($table);
00055             }
00056         }
00057         $this->tables = array();
00058     }
00059 
00069     private function get_test_table($suffix = '') {
00070         $dbman = $this->tdb->get_manager();
00071 
00072         $tablename = "unit_table";
00073         if ($suffix !== '') {
00074             $tablename .= $suffix;
00075         }
00076 
00077         $table = new xmldb_table($tablename);
00078         if ($dbman->table_exists($table)) {
00079             $dbman->drop_table($table);
00080         }
00081         $table->setComment("This is a test'n drop table. You can drop it safely");
00082         $this->tables[$tablename] = $tablename;
00083         return new xmldb_table($tablename);
00084     }
00085 
00086     protected function enable_debugging() {
00087         global $CFG;
00088 
00089         $this->olddebug   = $CFG->debug;       // Save current debug settings
00090         $this->olddisplay = $CFG->debugdisplay;
00091         $CFG->debug = DEBUG_DEVELOPER;
00092         $CFG->debugdisplay = true;
00093         ob_start(); // hide debug warning
00094 
00095     }
00096 
00097     protected function get_debugging() {
00098         global $CFG;
00099 
00100         $debuginfo = ob_get_contents();
00101         ob_end_clean();
00102         $CFG->debug = $this->olddebug;         // Restore original debug settings
00103         $CFG->debugdisplay = $this->olddisplay;
00104 
00105         return $debuginfo;
00106     }
00107 
00108     // NOTE: please keep order of test methods here matching the order of moodle_database class methods
00109 
00110     function test_diagnose() {
00111         $DB = $this->tdb;
00112         $result = $DB->diagnose();
00113         $this->assertNull($result, 'Database self diagnostics failed %s');
00114     }
00115 
00116     function test_get_server_info() {
00117         $DB = $this->tdb;
00118         $result = $DB->get_server_info();
00119         $this->assertTrue(is_array($result));
00120         $this->assertTrue(array_key_exists('description', $result));
00121         $this->assertTrue(array_key_exists('version', $result));
00122     }
00123 
00124     public function test_get_in_or_equal() {
00125         $DB = $this->tdb;
00126 
00127         // SQL_PARAMS_QM - IN or =
00128 
00129         // Correct usage of multiple values
00130         $in_values = array('value1', 'value2', '3', 4, null, false, true);
00131         list($usql, $params) = $DB->get_in_or_equal($in_values);
00132         $this->assertEqual('IN ('.implode(',',array_fill(0, count($in_values), '?')).')', $usql);
00133         $this->assertEqual(count($in_values), count($params));
00134         foreach ($params as $key => $value) {
00135             $this->assertIdentical($in_values[$key], $value);
00136         }
00137 
00138         // Correct usage of single value (in an array)
00139         $in_values = array('value1');
00140         list($usql, $params) = $DB->get_in_or_equal($in_values);
00141         $this->assertEqual("= ?", $usql);
00142         $this->assertEqual(1, count($params));
00143         $this->assertEqual($in_values[0], $params[0]);
00144 
00145         // Correct usage of single value
00146         $in_value = 'value1';
00147         list($usql, $params) = $DB->get_in_or_equal($in_values);
00148         $this->assertEqual("= ?", $usql);
00149         $this->assertEqual(1, count($params));
00150         $this->assertEqual($in_value, $params[0]);
00151 
00152         // SQL_PARAMS_QM - NOT IN or <>
00153 
00154         // Correct usage of multiple values
00155         $in_values = array('value1', 'value2', 'value3', 'value4');
00156         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
00157         $this->assertEqual("NOT IN (?,?,?,?)", $usql);
00158         $this->assertEqual(4, count($params));
00159         foreach ($params as $key => $value) {
00160             $this->assertEqual($in_values[$key], $value);
00161         }
00162 
00163         // Correct usage of single value (in array()
00164         $in_values = array('value1');
00165         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
00166         $this->assertEqual("<> ?", $usql);
00167         $this->assertEqual(1, count($params));
00168         $this->assertEqual($in_values[0], $params[0]);
00169 
00170         // Correct usage of single value
00171         $in_value = 'value1';
00172         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
00173         $this->assertEqual("<> ?", $usql);
00174         $this->assertEqual(1, count($params));
00175         $this->assertEqual($in_value, $params[0]);
00176 
00177         // SQL_PARAMS_NAMED - IN or =
00178 
00179         // Correct usage of multiple values
00180         $in_values = array('value1', 'value2', 'value3', 'value4');
00181         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
00182         $this->assertEqual(4, count($params));
00183         reset($in_values);
00184         $ps = array();
00185         foreach ($params as $key => $value) {
00186             $this->assertEqual(current($in_values), $value);
00187             next($in_values);
00188             $ps[] = ':'.$key;
00189         }
00190         $this->assertEqual("IN (".implode(',', $ps).")", $usql);
00191 
00192         // Correct usage of single values (in array)
00193         $in_values = array('value1');
00194         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
00195         $this->assertEqual(1, count($params));
00196         $value = reset($params);
00197         $key = key($params);
00198         $this->assertEqual("= :$key", $usql);
00199         $this->assertEqual($in_value, $value);
00200 
00201         // Correct usage of single value
00202         $in_value = 'value1';
00203         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
00204         $this->assertEqual(1, count($params));
00205         $value = reset($params);
00206         $key = key($params);
00207         $this->assertEqual("= :$key", $usql);
00208         $this->assertEqual($in_value, $value);
00209 
00210         // SQL_PARAMS_NAMED - NOT IN or <>
00211 
00212         // Correct usage of multiple values
00213         $in_values = array('value1', 'value2', 'value3', 'value4');
00214         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
00215         $this->assertEqual(4, count($params));
00216         reset($in_values);
00217         $ps = array();
00218         foreach ($params as $key => $value) {
00219             $this->assertEqual(current($in_values), $value);
00220             next($in_values);
00221             $ps[] = ':'.$key;
00222         }
00223         $this->assertEqual("NOT IN (".implode(',', $ps).")", $usql);
00224 
00225         // Correct usage of single values (in array)
00226         $in_values = array('value1');
00227         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
00228         $this->assertEqual(1, count($params));
00229         $value = reset($params);
00230         $key = key($params);
00231         $this->assertEqual("<> :$key", $usql);
00232         $this->assertEqual($in_value, $value);
00233 
00234         // Correct usage of single value
00235         $in_value = 'value1';
00236         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
00237         $this->assertEqual(1, count($params));
00238         $value = reset($params);
00239         $key = key($params);
00240         $this->assertEqual("<> :$key", $usql);
00241         $this->assertEqual($in_value, $value);
00242 
00243         // make sure the param names are unique
00244         list($usql1, $params1) = $DB->get_in_or_equal(array(1,2,3), SQL_PARAMS_NAMED, 'param');
00245         list($usql2, $params2) = $DB->get_in_or_equal(array(1,2,3), SQL_PARAMS_NAMED, 'param');
00246         $params1 = array_keys($params1);
00247         $params2 = array_keys($params2);
00248         $common = array_intersect($params1, $params2);
00249         $this->assertEqual(count($common), 0);
00250 
00251         // Some incorrect tests
00252 
00253         // Incorrect usage passing not-allowed params type
00254         $in_values = array(1, 2, 3);
00255         try {
00256             list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_DOLLAR, 'param', false);
00257             $this->fail('An Exception is missing, expected due to not supported SQL_PARAMS_DOLLAR');
00258         } catch (exception $e) {
00259             $this->assertTrue($e instanceof dml_exception);
00260             $this->assertEqual($e->errorcode, 'typenotimplement');
00261         }
00262 
00263         // Incorrect usage passing empty array
00264         $in_values = array();
00265         try {
00266             list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
00267             $this->fail('An Exception is missing, expected due to empty array of items');
00268         } catch (exception $e) {
00269             $this->assertTrue($e instanceof coding_exception);
00270         }
00271 
00272         // Test using $onemptyitems
00273 
00274         // Correct usage passing empty array and $onemptyitems = NULL (equal = true, QM)
00275         $in_values = array();
00276         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, NULL);
00277         $this->assertEqual(' IS NULL', $usql);
00278         $this->assertIdentical(array(), $params);
00279 
00280         // Correct usage passing empty array and $onemptyitems = NULL (equal = false, NAMED)
00281         $in_values = array();
00282         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, NULL);
00283         $this->assertEqual(' IS NOT NULL', $usql);
00284         $this->assertIdentical(array(), $params);
00285 
00286         // Correct usage passing empty array and $onemptyitems = true (equal = true, QM)
00287         $in_values = array();
00288         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, true);
00289         $this->assertEqual('= ?', $usql);
00290         $this->assertIdentical(array(true), $params);
00291 
00292         // Correct usage passing empty array and $onemptyitems = true (equal = false, NAMED)
00293         $in_values = array();
00294         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, true);
00295         $this->assertEqual(1, count($params));
00296         $value = reset($params);
00297         $key = key($params);
00298         $this->assertEqual('<> :'.$key, $usql);
00299         $this->assertIdentical($value, true);
00300 
00301         // Correct usage passing empty array and $onemptyitems = -1 (equal = true, QM)
00302         $in_values = array();
00303         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, -1);
00304         $this->assertEqual('= ?', $usql);
00305         $this->assertIdentical(array(-1), $params);
00306 
00307         // Correct usage passing empty array and $onemptyitems = -1 (equal = false, NAMED)
00308         $in_values = array();
00309         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, -1);
00310         $this->assertEqual(1, count($params));
00311         $value = reset($params);
00312         $key = key($params);
00313         $this->assertEqual('<> :'.$key, $usql);
00314         $this->assertIdentical($value, -1);
00315 
00316         // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = true, QM)
00317         $in_values = array();
00318         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, 'onevalue');
00319         $this->assertEqual('= ?', $usql);
00320         $this->assertIdentical(array('onevalue'), $params);
00321 
00322         // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = false, NAMED)
00323         $in_values = array();
00324         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, 'onevalue');
00325         $this->assertEqual(1, count($params));
00326         $value = reset($params);
00327         $key = key($params);
00328         $this->assertEqual('<> :'.$key, $usql);
00329         $this->assertIdentical($value, 'onevalue');
00330     }
00331 
00332     public function test_fix_table_names() {
00333         $DB = new moodle_database_for_testing();
00334         $prefix = $DB->get_prefix();
00335 
00336         // Simple placeholder
00337         $placeholder = "{user_123}";
00338         $this->assertIdentical($prefix."user_123", $DB->public_fix_table_names($placeholder));
00339 
00340         // wrong table name
00341         $placeholder = "{user-a}";
00342         $this->assertIdentical($placeholder, $DB->public_fix_table_names($placeholder));
00343 
00344         // wrong table name
00345         $placeholder = "{123user}";
00346         $this->assertIdentical($placeholder, $DB->public_fix_table_names($placeholder));
00347 
00348         // Full SQL
00349         $sql = "SELECT * FROM {user}, {funny_table_name}, {mdl_stupid_table} WHERE {user}.id = {funny_table_name}.userid";
00350         $expected = "SELECT * FROM {$prefix}user, {$prefix}funny_table_name, {$prefix}mdl_stupid_table WHERE {$prefix}user.id = {$prefix}funny_table_name.userid";
00351         $this->assertIdentical($expected, $DB->public_fix_table_names($sql));
00352     }
00353 
00354     function test_fix_sql_params() {
00355         $DB = $this->tdb;
00356 
00357         $table = $this->get_test_table();
00358         $tablename = $table->getName();
00359 
00360         // Correct table placeholder substitution
00361         $sql = "SELECT * FROM {{$tablename}}";
00362         $sqlarray = $DB->fix_sql_params($sql);
00363         $this->assertEqual("SELECT * FROM {$DB->get_prefix()}".$tablename, $sqlarray[0]);
00364 
00365         // Conversions of all param types
00366         $sql = array();
00367         $sql[SQL_PARAMS_NAMED]  = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = :param1, course = :param2";
00368         $sql[SQL_PARAMS_QM]     = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = ?, course = ?";
00369         $sql[SQL_PARAMS_DOLLAR] = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = \$1, course = \$2";
00370 
00371         $params = array();
00372         $params[SQL_PARAMS_NAMED]  = array('param1'=>'first record', 'param2'=>1);
00373         $params[SQL_PARAMS_QM]     = array('first record', 1);
00374         $params[SQL_PARAMS_DOLLAR] = array('first record', 1);
00375 
00376         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_NAMED], $params[SQL_PARAMS_NAMED]);
00377         $this->assertIdentical($rsql, $sql[$rtype]);
00378         $this->assertIdentical($rparams, $params[$rtype]);
00379 
00380         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_QM], $params[SQL_PARAMS_QM]);
00381         $this->assertIdentical($rsql, $sql[$rtype]);
00382         $this->assertIdentical($rparams, $params[$rtype]);
00383 
00384         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_DOLLAR], $params[SQL_PARAMS_DOLLAR]);
00385         $this->assertIdentical($rsql, $sql[$rtype]);
00386         $this->assertIdentical($rparams, $params[$rtype]);
00387 
00388 
00389         // Malformed table placeholder
00390         $sql = "SELECT * FROM [testtable]";
00391         $sqlarray = $DB->fix_sql_params($sql);
00392         $this->assertIdentical($sql, $sqlarray[0]);
00393 
00394 
00395         // Mixed param types (colon and dollar)
00396         $sql = "SELECT * FROM {{$tablename}} WHERE name = :param1, course = \$1";
00397         $params = array('param1' => 'record1', 'param2' => 3);
00398         try {
00399             $DB->fix_sql_params($sql, $params);
00400             $this->fail("Expecting an exception, none occurred");
00401         } catch (Exception $e) {
00402             $this->assertTrue($e instanceof dml_exception);
00403         }
00404 
00405         // Mixed param types (question and dollar)
00406         $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = \$1";
00407         $params = array('param1' => 'record2', 'param2' => 5);
00408         try {
00409             $DB->fix_sql_params($sql, $params);
00410             $this->fail("Expecting an exception, none occurred");
00411         } catch (Exception $e) {
00412             $this->assertTrue($e instanceof dml_exception);
00413         }
00414 
00415         // Too few params in sql
00416         $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = ?, id = ?";
00417         $params = array('record2', 3);
00418         try {
00419             $DB->fix_sql_params($sql, $params);
00420             $this->fail("Expecting an exception, none occurred");
00421         } catch (Exception $e) {
00422             $this->assertTrue($e instanceof dml_exception);
00423         }
00424 
00425         // Too many params in array: no error, just use what is necessary
00426         $params[] = 1;
00427         $params[] = time();
00428         try {
00429             $sqlarray = $DB->fix_sql_params($sql, $params);
00430             $this->assertTrue(is_array($sqlarray));
00431             $this->assertEqual(count($sqlarray[1]), 3);
00432         } catch (Exception $e) {
00433             $this->fail("Unexpected ".get_class($e)." exception");
00434         }
00435 
00436         // Named params missing from array
00437         $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
00438         $params = array('wrongname' => 'record1', 'course' => 1);
00439         try {
00440             $DB->fix_sql_params($sql, $params);
00441             $this->fail("Expecting an exception, none occurred");
00442         } catch (Exception $e) {
00443             $this->assertTrue($e instanceof dml_exception);
00444         }
00445 
00446         // Duplicate named param in query - this is a very important feature!!
00447         // it helps with debugging of sloppy code
00448         $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :name";
00449         $params = array('name' => 'record2', 'course' => 3);
00450         try {
00451             $DB->fix_sql_params($sql, $params);
00452             $this->fail("Expecting an exception, none occurred");
00453         } catch (Exception $e) {
00454             $this->assertTrue($e instanceof dml_exception);
00455         }
00456 
00457         // Extra named param is ignored
00458         $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
00459         $params = array('name' => 'record1', 'course' => 1, 'extrastuff'=>'haha');
00460         try {
00461             $sqlarray = $DB->fix_sql_params($sql, $params);
00462             $this->assertTrue(is_array($sqlarray));
00463             $this->assertEqual(count($sqlarray[1]), 2);
00464         } catch (Exception $e) {
00465             $this->fail("Unexpected ".get_class($e)." exception");
00466         }
00467 
00468         // Params exceeding 30 chars length
00469         $sql = "SELECT * FROM {{$tablename}} WHERE name = :long_placeholder_with_more_than_30";
00470         $params = array('long_placeholder_with_more_than_30' => 'record1');
00471         try {
00472             $DB->fix_sql_params($sql, $params);
00473             $this->fail("Expecting an exception, none occurred");
00474         } catch (Exception $e) {
00475             $this->assertTrue($e instanceof coding_exception);
00476         }
00477 
00478         // Booleans in NAMED params are casting to 1/0 int
00479         $sql = "SELECT * FROM {{$tablename}} WHERE course = ? OR course = ?";
00480         $params = array(true, false);
00481         list($sql, $params) = $DB->fix_sql_params($sql, $params);
00482         $this->assertTrue(reset($params) === 1);
00483         $this->assertTrue(next($params) === 0);
00484 
00485         // Booleans in QM params are casting to 1/0 int
00486         $sql = "SELECT * FROM {{$tablename}} WHERE course = :course1 OR course = :course2";
00487         $params = array('course1' => true, 'course2' => false);
00488         list($sql, $params) = $DB->fix_sql_params($sql, $params);
00489         $this->assertTrue(reset($params) === 1);
00490         $this->assertTrue(next($params) === 0);
00491 
00492         // Booleans in DOLLAR params are casting to 1/0 int
00493         $sql = "SELECT * FROM {{$tablename}} WHERE course = \$1 OR course = \$2";
00494         $params = array(true, false);
00495         list($sql, $params) = $DB->fix_sql_params($sql, $params);
00496         $this->assertTrue(reset($params) === 1);
00497         $this->assertTrue(next($params) === 0);
00498 
00499         // No data types are touched except bool
00500         $sql = "SELECT * FROM {{$tablename}} WHERE name IN (?,?,?,?,?,?)";
00501         $inparams = array('abc', 'ABC', NULL, '1', 1, 1.4);
00502         list($sql, $params) = $DB->fix_sql_params($sql, $inparams);
00503         $this->assertIdentical(array_values($params), array_values($inparams));
00504     }
00505 
00506     public function test_strtok() {
00507         // strtok was previously used by bound emulation, make sure it is not used any more
00508         $DB = $this->tdb;
00509         $dbman = $this->tdb->get_manager();
00510 
00511         $table = $this->get_test_table();
00512         $tablename = $table->getName();
00513 
00514         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
00515         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
00516         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
00517         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
00518         $dbman->create_table($table);
00519 
00520         $str = 'a?b?c?d';
00521         $this->assertIdentical(strtok($str, '?'), 'a');
00522 
00523         $DB->get_records($tablename, array('id'=>1));
00524 
00525         $this->assertIdentical(strtok('?'), 'b');
00526     }
00527 
00528     public function test_tweak_param_names() {
00529         // Note the tweak_param_names() method is only available in the oracle driver,
00530         // hence we look for expected results indirectly, by testing various DML methods
00531         // with some "extreme" conditions causing the tweak to happen.
00532         $DB = $this->tdb;
00533         $dbman = $this->tdb->get_manager();
00534 
00535         $table = $this->get_test_table();
00536         $tablename = $table->getName();
00537 
00538         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
00539         // Add some columns with 28 chars in the name
00540         $table->add_field('long_int_columnname_with_28c', XMLDB_TYPE_INTEGER, '10');
00541         $table->add_field('long_dec_columnname_with_28c', XMLDB_TYPE_NUMBER, '10,2');
00542         $table->add_field('long_str_columnname_with_28c', XMLDB_TYPE_CHAR, '100');
00543         // Add some columns with 30 chars in the name
00544         $table->add_field('long_int_columnname_with_30cxx', XMLDB_TYPE_INTEGER, '10');
00545         $table->add_field('long_dec_columnname_with_30cxx', XMLDB_TYPE_NUMBER, '10,2');
00546         $table->add_field('long_str_columnname_with_30cxx', XMLDB_TYPE_CHAR, '100');
00547 
00548         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
00549 
00550         $dbman->create_table($table);
00551 
00552         $this->assertTrue($dbman->table_exists($tablename));
00553 
00554         // Test insert record
00555         $rec1 = new stdClass();
00556         $rec1->long_int_columnname_with_28c = 28;
00557         $rec1->long_dec_columnname_with_28c = 28.28;
00558         $rec1->long_str_columnname_with_28c = '28';
00559         $rec1->long_int_columnname_with_30cxx = 30;
00560         $rec1->long_dec_columnname_with_30cxx = 30.30;
00561         $rec1->long_str_columnname_with_30cxx = '30';
00562 
00563         // insert_record()
00564         $rec1->id = $DB->insert_record($tablename, $rec1);
00565         $this->assertEqual($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
00566 
00567         // update_record()
00568         $DB->update_record($tablename, $rec1);
00569         $this->assertEqual($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
00570 
00571         // set_field()
00572         $rec1->long_int_columnname_with_28c = 280;
00573         $DB->set_field($tablename, 'long_int_columnname_with_28c', $rec1->long_int_columnname_with_28c,
00574             array('id' => $rec1->id, 'long_int_columnname_with_28c' => 28));
00575         $rec1->long_dec_columnname_with_28c = 280.28;
00576         $DB->set_field($tablename, 'long_dec_columnname_with_28c', $rec1->long_dec_columnname_with_28c,
00577             array('id' => $rec1->id, 'long_dec_columnname_with_28c' => 28.28));
00578         $rec1->long_str_columnname_with_28c = '280';
00579         $DB->set_field($tablename, 'long_str_columnname_with_28c', $rec1->long_str_columnname_with_28c,
00580             array('id' => $rec1->id, 'long_str_columnname_with_28c' => '28'));
00581         $rec1->long_int_columnname_with_30cxx = 300;
00582         $DB->set_field($tablename, 'long_int_columnname_with_30cxx', $rec1->long_int_columnname_with_30cxx,
00583             array('id' => $rec1->id, 'long_int_columnname_with_30cxx' => 30));
00584         $rec1->long_dec_columnname_with_30cxx = 300.30;
00585         $DB->set_field($tablename, 'long_dec_columnname_with_30cxx', $rec1->long_dec_columnname_with_30cxx,
00586             array('id' => $rec1->id, 'long_dec_columnname_with_30cxx' => 30.30));
00587         $rec1->long_str_columnname_with_30cxx = '300';
00588         $DB->set_field($tablename, 'long_str_columnname_with_30cxx', $rec1->long_str_columnname_with_30cxx,
00589             array('id' => $rec1->id, 'long_str_columnname_with_30cxx' => '30'));
00590         $this->assertEqual($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
00591 
00592         // delete_records()
00593         $rec2 = $DB->get_record($tablename, array('id' => $rec1->id));
00594         $rec2->id = $DB->insert_record($tablename, $rec2);
00595         $this->assertEqual(2, $DB->count_records($tablename));
00596         $DB->delete_records($tablename, (array) $rec2);
00597         $this->assertEqual(1, $DB->count_records($tablename));
00598 
00599         // get_recordset()
00600         $rs = $DB->get_recordset($tablename, (array) $rec1);
00601         $iterations = 0;
00602         foreach ($rs as $rec2) {
00603             $iterations++;
00604         }
00605         $rs->close();
00606         $this->assertEqual(1, $iterations);
00607         $this->assertEqual($rec1, $rec2);
00608 
00609         // get_records()
00610         $recs = $DB->get_records($tablename, (array) $rec1);
00611         $this->assertEqual(1, count($recs));
00612         $this->assertEqual($rec1, reset($recs));
00613 
00614         // get_fieldset_select()
00615         $select = 'id = :id AND
00616                    long_int_columnname_with_28c = :long_int_columnname_with_28c AND
00617                    long_dec_columnname_with_28c = :long_dec_columnname_with_28c AND
00618                    long_str_columnname_with_28c = :long_str_columnname_with_28c AND
00619                    long_int_columnname_with_30cxx = :long_int_columnname_with_30cxx AND
00620                    long_dec_columnname_with_30cxx = :long_dec_columnname_with_30cxx AND
00621                    long_str_columnname_with_30cxx = :long_str_columnname_with_30cxx';
00622         $fields = $DB->get_fieldset_select($tablename, 'long_int_columnname_with_28c', $select, (array)$rec1);
00623         $this->assertEqual(1, count($fields));
00624         $this->assertEqual($rec1->long_int_columnname_with_28c, reset($fields));
00625         $fields = $DB->get_fieldset_select($tablename, 'long_dec_columnname_with_28c', $select, (array)$rec1);
00626         $this->assertEqual($rec1->long_dec_columnname_with_28c, reset($fields));
00627         $fields = $DB->get_fieldset_select($tablename, 'long_str_columnname_with_28c', $select, (array)$rec1);
00628         $this->assertEqual($rec1->long_str_columnname_with_28c, reset($fields));
00629         $fields = $DB->get_fieldset_select($tablename, 'long_int_columnname_with_30cxx', $select, (array)$rec1);
00630         $this->assertEqual($rec1->long_int_columnname_with_30cxx, reset($fields));
00631         $fields = $DB->get_fieldset_select($tablename, 'long_dec_columnname_with_30cxx', $select, (array)$rec1);
00632         $this->assertEqual($rec1->long_dec_columnname_with_30cxx, reset($fields));
00633         $fields = $DB->get_fieldset_select($tablename, 'long_str_columnname_with_30cxx', $select, (array)$rec1);
00634         $this->assertEqual($rec1->long_str_columnname_with_30cxx, reset($fields));
00635 
00636         // overlapping placeholders (progressive str_replace)
00637         $overlapselect = 'id = :p AND
00638                    long_int_columnname_with_28c = :param1 AND
00639                    long_dec_columnname_with_28c = :param2 AND
00640                    long_str_columnname_with_28c = :param_with_29_characters_long AND
00641                    long_int_columnname_with_30cxx = :param_with_30_characters_long_ AND
00642                    long_dec_columnname_with_30cxx = :param_ AND
00643                    long_str_columnname_with_30cxx = :param__';
00644         $overlapparams = array(
00645                 'p' => $rec1->id,
00646                 'param1' => $rec1->long_int_columnname_with_28c,
00647                 'param2' => $rec1->long_dec_columnname_with_28c,
00648                 'param_with_29_characters_long' => $rec1->long_str_columnname_with_28c,
00649                 'param_with_30_characters_long_' => $rec1->long_int_columnname_with_30cxx,
00650                 'param_' => $rec1->long_dec_columnname_with_30cxx,
00651                 'param__' => $rec1->long_str_columnname_with_30cxx);
00652         $recs = $DB->get_records_select($tablename, $overlapselect, $overlapparams);
00653         $this->assertEqual(1, count($recs));
00654         $this->assertEqual($rec1, reset($recs));
00655 
00656         // execute()
00657         $DB->execute("DELETE FROM {{$tablename}} WHERE $select", (array)$rec1);
00658         $this->assertEqual(0, $DB->count_records($tablename));
00659     }
00660 
00661     public function test_get_tables() {
00662         $DB = $this->tdb;
00663         $dbman = $this->tdb->get_manager();
00664 
00665         // Need to test with multiple DBs
00666         $table = $this->get_test_table();
00667         $tablename = $table->getName();
00668 
00669         $original_count = count($DB->get_tables());
00670 
00671         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
00672         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
00673 
00674         $dbman->create_table($table);
00675         $this->assertTrue(count($DB->get_tables()) == $original_count + 1);
00676 
00677         $dbman->drop_table($table);
00678         $this->assertTrue(count($DB->get_tables()) == $original_count);
00679     }
00680 
00681     public function test_get_indexes() {
00682         $DB = $this->tdb;
00683         $dbman = $this->tdb->get_manager();
00684 
00685         $table = $this->get_test_table();
00686         $tablename = $table->getName();
00687 
00688         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
00689         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
00690         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
00691         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
00692         $table->add_index('course-id', XMLDB_INDEX_UNIQUE, array('course', 'id'));
00693         $dbman->create_table($table);
00694 
00695         $indices = $DB->get_indexes($tablename);
00696         $this->assertTrue(is_array($indices));
00697         $this->assertEqual(count($indices), 2);
00698         // we do not care about index names for now
00699         $first = array_shift($indices);
00700         $second = array_shift($indices);
00701         if (count($first['columns']) == 2) {
00702             $composed = $first;
00703             $single   = $second;
00704         } else {
00705             $composed = $second;
00706             $single   = $first;
00707         }
00708         $this->assertFalse($single['unique']);
00709         $this->assertTrue($composed['unique']);
00710         $this->assertEqual(1, count($single['columns']));
00711         $this->assertEqual(2, count($composed['columns']));
00712         $this->assertEqual('course', $single['columns'][0]);
00713         $this->assertEqual('course', $composed['columns'][0]);
00714         $this->assertEqual('id', $composed['columns'][1]);
00715     }
00716 
00717     public function test_get_columns() {
00718         $DB = $this->tdb;
00719         $dbman = $this->tdb->get_manager();
00720 
00721         $table = $this->get_test_table();
00722         $tablename = $table->getName();
00723 
00724         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
00725         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
00726         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
00727         $table->add_field('description', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
00728         $table->add_field('enumfield', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'test2');
00729         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
00730         $table->add_field('onefloat', XMLDB_TYPE_FLOAT, '10,2', null, null, null, 300);
00731         $table->add_field('anotherfloat', XMLDB_TYPE_FLOAT, null, null, null, null, 400);
00732         $table->add_field('negativedfltint', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '-1');
00733         $table->add_field('negativedfltnumber', XMLDB_TYPE_NUMBER, '10', null, XMLDB_NOTNULL, null, '-2');
00734         $table->add_field('negativedfltfloat', XMLDB_TYPE_FLOAT, '10', null, XMLDB_NOTNULL, null, '-3');
00735         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
00736         $dbman->create_table($table);
00737 
00738         $columns = $DB->get_columns($tablename);
00739         $this->assertTrue(is_array($columns));
00740 
00741         $fields = $table->getFields();
00742         $this->assertEqual(count($columns), count($fields));
00743 
00744         $field = $columns['id'];
00745         $this->assertEqual('R', $field->meta_type);
00746         $this->assertTrue($field->auto_increment);
00747         $this->assertTrue($field->unique);
00748 
00749         $field = $columns['course'];
00750         $this->assertEqual('I', $field->meta_type);
00751         $this->assertFalse($field->auto_increment);
00752         $this->assertTrue($field->has_default);
00753         $this->assertEqual(0, $field->default_value);
00754         $this->assertTrue($field->not_null);
00755 
00756         $field = $columns['name'];
00757         $this->assertEqual('C', $field->meta_type);
00758         $this->assertFalse($field->auto_increment);
00759         $this->assertEqual(255, $field->max_length);
00760         $this->assertTrue($field->has_default);
00761         $this->assertIdentical('lala', $field->default_value);
00762         $this->assertFalse($field->not_null);
00763 
00764         $field = $columns['description'];
00765         $this->assertEqual('X', $field->meta_type);
00766         $this->assertFalse($field->auto_increment);
00767         $this->assertFalse($field->has_default);
00768         $this->assertIdentical(null, $field->default_value);
00769         $this->assertFalse($field->not_null);
00770 
00771         $field = $columns['enumfield'];
00772         $this->assertEqual('C', $field->meta_type);
00773         $this->assertFalse($field->auto_increment);
00774         $this->assertIdentical('test2', $field->default_value);
00775         $this->assertTrue($field->not_null);
00776 
00777         $field = $columns['onenum'];
00778         $this->assertEqual('N', $field->meta_type);
00779         $this->assertFalse($field->auto_increment);
00780         $this->assertEqual(10, $field->max_length);
00781         $this->assertEqual(2, $field->scale);
00782         $this->assertTrue($field->has_default);
00783         $this->assertEqual(200.0, $field->default_value);
00784         $this->assertFalse($field->not_null);
00785 
00786         $field = $columns['onefloat'];
00787         $this->assertEqual('N', $field->meta_type);
00788         $this->assertFalse($field->auto_increment);
00789         $this->assertTrue($field->has_default);
00790         $this->assertEqual(300.0, $field->default_value);
00791         $this->assertFalse($field->not_null);
00792 
00793         $field = $columns['anotherfloat'];
00794         $this->assertEqual('N', $field->meta_type);
00795         $this->assertFalse($field->auto_increment);
00796         $this->assertTrue($field->has_default);
00797         $this->assertEqual(400.0, $field->default_value);
00798         $this->assertFalse($field->not_null);
00799 
00800         // Test negative defaults in numerical columns
00801         $field = $columns['negativedfltint'];
00802         $this->assertTrue($field->has_default);
00803         $this->assertEqual(-1, $field->default_value);
00804 
00805         $field = $columns['negativedfltnumber'];
00806         $this->assertTrue($field->has_default);
00807         $this->assertEqual(-2, $field->default_value);
00808 
00809         $field = $columns['negativedfltfloat'];
00810         $this->assertTrue($field->has_default);
00811         $this->assertEqual(-3, $field->default_value);
00812 
00813         for ($i = 0; $i < count($columns); $i++) {
00814             if ($i == 0) {
00815                 $next_column = reset($columns);
00816                 $next_field  = reset($fields);
00817             } else {
00818                 $next_column = next($columns);
00819                 $next_field  = next($fields);
00820             }
00821 
00822             $this->assertEqual($next_column->name, $next_field->name);
00823         }
00824 
00825         // Test get_columns for non-existing table returns empty array. MDL-30147
00826         $columns = $DB->get_columns('xxxx');
00827         $this->assertEqual(array(), $columns);
00828     }
00829 
00830     public function test_get_manager() {
00831         $DB = $this->tdb;
00832         $dbman = $this->tdb->get_manager();
00833 
00834         $this->assertTrue($dbman instanceof database_manager);
00835     }
00836 
00837     public function test_setup_is_unicodedb() {
00838         $DB = $this->tdb;
00839         $this->assertTrue($DB->setup_is_unicodedb());
00840     }
00841 
00842     public function test_set_debug() { //tests get_debug() too
00843         $DB = $this->tdb;
00844         $dbman = $this->tdb->get_manager();
00845 
00846         $table = $this->get_test_table();
00847         $tablename = $table->getName();
00848 
00849         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
00850         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
00851         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
00852         $dbman->create_table($table);
00853 
00854         $sql = "SELECT * FROM {{$tablename}}";
00855 
00856         $prevdebug = $DB->get_debug();
00857 
00858         ob_start();
00859         $DB->set_debug(true);
00860         $this->assertTrue($DB->get_debug());
00861         $DB->execute($sql);
00862         $DB->set_debug(false);
00863         $this->assertFalse($DB->get_debug());
00864         $debuginfo = ob_get_contents();
00865         ob_end_clean();
00866         $this->assertFalse($debuginfo === '');
00867 
00868         ob_start();
00869         $DB->execute($sql);
00870         $debuginfo = ob_get_contents();
00871         ob_end_clean();
00872         $this->assertTrue($debuginfo === '');
00873 
00874         $DB->set_debug($prevdebug);
00875     }
00876 
00877     public function test_execute() {
00878         $DB = $this->tdb;
00879         $dbman = $this->tdb->get_manager();
00880 
00881         $table1 = $this->get_test_table('1');
00882         $tablename1 = $table1->getName();
00883         $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
00884         $table1->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
00885         $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
00886         $table1->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
00887         $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
00888         $dbman->create_table($table1);
00889 
00890         $table2 = $this->get_test_table('2');
00891         $tablename2 = $table2->getName();
00892         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
00893         $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
00894         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
00895         $dbman->create_table($table2);
00896 
00897         $DB->insert_record($tablename1, array('course' => 3, 'name' => 'aaa'));
00898         $DB->insert_record($tablename1, array('course' => 1, 'name' => 'bbb'));
00899         $DB->insert_record($tablename1, array('course' => 7, 'name' => 'ccc'));
00900         $DB->insert_record($tablename1, array('course' => 3, 'name' => 'ddd'));
00901 
00902         // select results are ignored
00903         $sql = "SELECT * FROM {{$tablename1}} WHERE course = :course";
00904         $this->assertTrue($DB->execute($sql, array('course'=>3)));
00905 
00906         // throw exception on error
00907         $sql = "XXUPDATE SET XSSD";
00908         try {
00909             $DB->execute($sql);
00910             $this->fail("Expecting an exception, none occurred");
00911         } catch (Exception $e) {
00912             $this->assertTrue($e instanceof dml_exception);
00913         }
00914 
00915         // update records
00916         $sql = "UPDATE {{$tablename1}}
00917                    SET course = 6
00918                  WHERE course = ?";
00919         $this->assertTrue($DB->execute($sql, array('3')));
00920         $this->assertEqual($DB->count_records($tablename1, array('course' => 6)), 2);
00921 
00922         // update records with subquery condition
00923         // confirm that the option not using table aliases is cross-db
00924         $sql = "UPDATE {{$tablename1}}
00925                    SET course = 0
00926                  WHERE NOT EXISTS (
00927                            SELECT course
00928                              FROM {{$tablename2}} tbl2
00929                             WHERE tbl2.course = {{$tablename1}}.course
00930                               AND 1 = 0)"; // Really we don't update anything, but verify the syntax is allowed
00931         $this->assertTrue($DB->execute($sql));
00932 
00933         // insert from one into second table
00934         $sql = "INSERT INTO {{$tablename2}} (course)
00935 
00936                 SELECT course
00937                   FROM {{$tablename1}}";
00938         $this->assertTrue($DB->execute($sql));
00939         $this->assertEqual($DB->count_records($tablename2), 4);
00940     }
00941 
00942     public function test_get_recordset() {
00943         $DB = $this->tdb;
00944         $dbman = $DB->get_manager();
00945 
00946         $table = $this->get_test_table();
00947         $tablename = $table->getName();
00948 
00949         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
00950         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
00951         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
00952         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
00953         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
00954         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
00955         $dbman->create_table($table);
00956 
00957         $data = array(array('id' => 1, 'course' => 3, 'name' => 'record1', 'onetext'=>'abc'),
00958                       array('id' => 2, 'course' => 3, 'name' => 'record2', 'onetext'=>'abcd'),
00959                       array('id' => 3, 'course' => 5, 'name' => 'record3', 'onetext'=>'abcde'));
00960 
00961         foreach ($data as $record) {
00962             $DB->insert_record($tablename, $record);
00963         }
00964 
00965         // standard recordset iteration
00966         $rs = $DB->get_recordset($tablename);
00967         $this->assertTrue($rs instanceof moodle_recordset);
00968         reset($data);
00969         foreach($rs as $record) {
00970             $data_record = current($data);
00971             foreach ($record as $k => $v) {
00972                 $this->assertEqual($data_record[$k], $v);
00973             }
00974             next($data);
00975         }
00976         $rs->close();
00977 
00978         // iterator style usage
00979         $rs = $DB->get_recordset($tablename);
00980         $this->assertTrue($rs instanceof moodle_recordset);
00981         reset($data);
00982         while ($rs->valid()) {
00983             $record = $rs->current();
00984             $data_record = current($data);
00985             foreach ($record as $k => $v) {
00986                 $this->assertEqual($data_record[$k], $v);
00987             }
00988             next($data);
00989             $rs->next();
00990         }
00991         $rs->close();
00992 
00993         // make sure rewind is ignored
00994         $rs = $DB->get_recordset($tablename);
00995         $this->assertTrue($rs instanceof moodle_recordset);
00996         reset($data);
00997         $i = 0;
00998         foreach($rs as $record) {
00999             $i++;
01000             $rs->rewind();
01001             if ($i > 10) {
01002                 $this->fail('revind not ignored in recordsets');
01003                 break;
01004             }
01005             $data_record = current($data);
01006             foreach ($record as $k => $v) {
01007                 $this->assertEqual($data_record[$k], $v);
01008             }
01009             next($data);
01010         }
01011         $rs->close();
01012 
01013         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
01014         $conditions = array('onetext' => '1');
01015         try {
01016             $rs = $DB->get_recordset($tablename, $conditions);
01017             if (debugging()) {
01018                 // only in debug mode - hopefully all devs test code in debug mode...
01019                 $this->fail('An Exception is missing, expected due to equating of text fields');
01020             }
01021         } catch (exception $e) {
01022             $this->assertTrue($e instanceof dml_exception);
01023             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
01024         }
01025 
01026         // notes:
01027         //  * limits are tested in test_get_recordset_sql()
01028         //  * where_clause() is used internally and is tested in test_get_records()
01029     }
01030 
01031     public function test_get_recordset_iterator_keys() {
01032         $DB = $this->tdb;
01033         $dbman = $DB->get_manager();
01034 
01035         $table = $this->get_test_table();
01036         $tablename = $table->getName();
01037 
01038         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01039         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01040         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
01041         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
01042         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01043         $dbman->create_table($table);
01044 
01045         $data = array(array('id'=> 1, 'course' => 3, 'name' => 'record1'),
01046                       array('id'=> 2, 'course' => 3, 'name' => 'record2'),
01047                       array('id'=> 3, 'course' => 5, 'name' => 'record3'));
01048         foreach ($data as $record) {
01049             $DB->insert_record($tablename, $record);
01050         }
01051 
01052         // Test repeated numeric keys are returned ok
01053         $rs = $DB->get_recordset($tablename, NULL, NULL, 'course, name, id');
01054 
01055         reset($data);
01056         $count = 0;
01057         foreach($rs as $key => $record) {
01058             $data_record = current($data);
01059             $this->assertEqual($data_record['course'], $key);
01060             next($data);
01061             $count++;
01062         }
01063         $rs->close();
01064         $this->assertEqual($count, 3);
01065 
01066         // Test string keys are returned ok
01067         $rs = $DB->get_recordset($tablename, NULL, NULL, 'name, course, id');
01068 
01069         reset($data);
01070         $count = 0;
01071         foreach($rs as $key => $record) {
01072             $data_record = current($data);
01073             $this->assertEqual($data_record['name'], $key);
01074             next($data);
01075             $count++;
01076         }
01077         $rs->close();
01078         $this->assertEqual($count, 3);
01079 
01080         // Test numeric not starting in 1 keys are returned ok
01081         $rs = $DB->get_recordset($tablename, NULL, 'id DESC', 'id, course, name');
01082 
01083         $data = array_reverse($data);
01084         reset($data);
01085         $count = 0;
01086         foreach($rs as $key => $record) {
01087             $data_record = current($data);
01088             $this->assertEqual($data_record['id'], $key);
01089             next($data);
01090             $count++;
01091         }
01092         $rs->close();
01093         $this->assertEqual($count, 3);
01094     }
01095 
01096     public function test_get_recordset_list() {
01097         $DB = $this->tdb;
01098         $dbman = $DB->get_manager();
01099 
01100         $table = $this->get_test_table();
01101         $tablename = $table->getName();
01102 
01103         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01104         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01105         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
01106         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01107         $dbman->create_table($table);
01108 
01109         $DB->insert_record($tablename, array('course' => 3));
01110         $DB->insert_record($tablename, array('course' => 3));
01111         $DB->insert_record($tablename, array('course' => 5));
01112         $DB->insert_record($tablename, array('course' => 2));
01113 
01114         $rs = $DB->get_recordset_list($tablename, 'course', array(3, 2));
01115 
01116         $counter = 0;
01117         foreach ($rs as $record) {
01118             $counter++;
01119         }
01120         $this->assertEqual(3, $counter);
01121         $rs->close();
01122 
01123         $rs = $DB->get_recordset_list($tablename, 'course',array()); 
01124 
01125         $counter = 0;
01126         foreach ($rs as $record) {
01127             $counter++;
01128         }
01129         $rs->close();
01130         $this->assertEqual(0, $counter);
01131 
01132         // notes:
01133         //  * limits are tested in test_get_recordset_sql()
01134         //  * where_clause() is used internally and is tested in test_get_records()
01135     }
01136 
01137     public function test_get_recordset_select() {
01138         $DB = $this->tdb;
01139         $dbman = $DB->get_manager();
01140 
01141         $table = $this->get_test_table();
01142         $tablename = $table->getName();
01143 
01144         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01145         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01146         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01147         $dbman->create_table($table);
01148 
01149         $DB->insert_record($tablename, array('course' => 3));
01150         $DB->insert_record($tablename, array('course' => 3));
01151         $DB->insert_record($tablename, array('course' => 5));
01152         $DB->insert_record($tablename, array('course' => 2));
01153 
01154         $rs = $DB->get_recordset_select($tablename, '');
01155         $counter = 0;
01156         foreach ($rs as $record) {
01157             $counter++;
01158         }
01159         $rs->close();
01160         $this->assertEqual(4, $counter);
01161 
01162         $this->assertTrue($rs = $DB->get_recordset_select($tablename, 'course = 3'));
01163         $counter = 0;
01164         foreach ($rs as $record) {
01165             $counter++;
01166         }
01167         $rs->close();
01168         $this->assertEqual(2, $counter);
01169 
01170         // notes:
01171         //  * limits are tested in test_get_recordset_sql()
01172     }
01173 
01174     public function test_get_recordset_sql() {
01175         $DB = $this->tdb;
01176         $dbman = $DB->get_manager();
01177 
01178         $table = $this->get_test_table();
01179         $tablename = $table->getName();
01180 
01181         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01182         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01183         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01184         $dbman->create_table($table);
01185 
01186         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
01187         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
01188         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
01189         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
01190         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
01191         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
01192         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
01193 
01194         $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
01195         $counter = 0;
01196         foreach ($rs as $record) {
01197             $counter++;
01198         }
01199         $rs->close();
01200         $this->assertEqual(2, $counter);
01201 
01202         // limits - only need to test this case, the rest have been tested by test_get_records_sql()
01203         // only limitfrom = skips that number of records
01204         $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
01205         $records = array();
01206         foreach($rs as $key => $record) {
01207             $records[$key] = $record;
01208         }
01209         $rs->close();
01210         $this->assertEqual(5, count($records));
01211         $this->assertEqual($inskey3, reset($records)->id);
01212         $this->assertEqual($inskey7, end($records)->id);
01213 
01214         // note: fetching nulls, empties, LOBs already tested by test_insert_record() no needed here
01215     }
01216 
01217     public function test_get_records() {
01218         $DB = $this->tdb;
01219         $dbman = $DB->get_manager();
01220 
01221         $table = $this->get_test_table();
01222         $tablename = $table->getName();
01223 
01224         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01225         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01226         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
01227         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01228         $dbman->create_table($table);
01229 
01230         $DB->insert_record($tablename, array('course' => 3));
01231         $DB->insert_record($tablename, array('course' => 3));
01232         $DB->insert_record($tablename, array('course' => 5));
01233         $DB->insert_record($tablename, array('course' => 2));
01234 
01235         // All records
01236         $records = $DB->get_records($tablename);
01237         $this->assertEqual(4, count($records));
01238         $this->assertEqual(3, $records[1]->course);
01239         $this->assertEqual(3, $records[2]->course);
01240         $this->assertEqual(5, $records[3]->course);
01241         $this->assertEqual(2, $records[4]->course);
01242 
01243         // Records matching certain conditions
01244         $records = $DB->get_records($tablename, array('course' => 3));
01245         $this->assertEqual(2, count($records));
01246         $this->assertEqual(3, $records[1]->course);
01247         $this->assertEqual(3, $records[2]->course);
01248 
01249         // All records sorted by course
01250         $records = $DB->get_records($tablename, null, 'course');
01251         $this->assertEqual(4, count($records));
01252         $current_record = reset($records);
01253         $this->assertEqual(4, $current_record->id);
01254         $current_record = next($records);
01255         $this->assertEqual(1, $current_record->id);
01256         $current_record = next($records);
01257         $this->assertEqual(2, $current_record->id);
01258         $current_record = next($records);
01259         $this->assertEqual(3, $current_record->id);
01260 
01261         // All records, but get only one field
01262         $records = $DB->get_records($tablename, null, '', 'id');
01263         $this->assertFalse(isset($records[1]->course));
01264         $this->assertTrue(isset($records[1]->id));
01265         $this->assertEqual(4, count($records));
01266 
01267         // Booleans into params
01268         $records = $DB->get_records($tablename, array('course' => true));
01269         $this->assertEqual(0, count($records));
01270         $records = $DB->get_records($tablename, array('course' => false));
01271         $this->assertEqual(0, count($records));
01272 
01273         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
01274         $conditions = array('onetext' => '1');
01275         try {
01276             $records = $DB->get_records($tablename, $conditions);
01277             if (debugging()) {
01278                 // only in debug mode - hopefully all devs test code in debug mode...
01279                 $this->fail('An Exception is missing, expected due to equating of text fields');
01280             }
01281         } catch (exception $e) {
01282             $this->assertTrue($e instanceof dml_exception);
01283             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
01284         }
01285 
01286         // test get_records passing non-existing table
01287         // with params
01288         try {
01289             $records = $DB->get_records('xxxx', array('id' => 0));
01290             $this->fail('An Exception is missing, expected due to query against non-existing table');
01291         } catch (exception $e) {
01292             $this->assertTrue($e instanceof dml_exception);
01293             if (debugging()) {
01294                 // information for developers only, normal users get general error message
01295                 $this->assertEqual($e->errorcode, 'ddltablenotexist');
01296             }
01297         }
01298         // and without params
01299         try {
01300             $records = $DB->get_records('xxxx', array());
01301             $this->fail('An Exception is missing, expected due to query against non-existing table');
01302         } catch (exception $e) {
01303             $this->assertTrue($e instanceof dml_exception);
01304             if (debugging()) {
01305                 // information for developers only, normal users get general error message
01306                 $this->assertEqual($e->errorcode, 'ddltablenotexist');
01307             }
01308         }
01309 
01310         // test get_records passing non-existing column
01311         try {
01312             $records = $DB->get_records($tablename, array('xxxx' => 0));
01313             $this->fail('An Exception is missing, expected due to query against non-existing column');
01314         } catch (exception $e) {
01315             $this->assertTrue($e instanceof dml_exception);
01316             if (debugging()) {
01317                 // information for developers only, normal users get general error message
01318                 $this->assertEqual($e->errorcode, 'ddlfieldnotexist');
01319             }
01320         }
01321 
01322         // note: delegate limits testing to test_get_records_sql()
01323     }
01324 
01325     public function test_get_records_list() {
01326         $DB = $this->tdb;
01327         $dbman = $DB->get_manager();
01328 
01329         $table = $this->get_test_table();
01330         $tablename = $table->getName();
01331 
01332         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01333         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01334         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01335         $dbman->create_table($table);
01336 
01337         $DB->insert_record($tablename, array('course' => 3));
01338         $DB->insert_record($tablename, array('course' => 3));
01339         $DB->insert_record($tablename, array('course' => 5));
01340         $DB->insert_record($tablename, array('course' => 2));
01341 
01342         $records = $DB->get_records_list($tablename, 'course', array(3, 2));
01343         $this->assertTrue(is_array($records));
01344         $this->assertEqual(3, count($records));
01345         $this->assertEqual(1, reset($records)->id);
01346         $this->assertEqual(2, next($records)->id);
01347         $this->assertEqual(4, next($records)->id);
01348 
01349         $this->assertIdentical(array(), $records = $DB->get_records_list($tablename, 'course', array())); 
01350         $this->assertEqual(0, count($records));
01351 
01352         // note: delegate limits testing to test_get_records_sql()
01353     }
01354 
01355     public function test_get_records_sql() {
01356         $DB = $this->tdb;
01357         $dbman = $DB->get_manager();
01358 
01359         $table = $this->get_test_table();
01360         $tablename = $table->getName();
01361 
01362         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01363         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01364         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01365         $dbman->create_table($table);
01366 
01367         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
01368         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
01369         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
01370         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
01371         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
01372         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
01373         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
01374 
01375         $table2 = $this->get_test_table("2");
01376         $tablename2 = $table2->getName();
01377         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01378         $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01379         $table2->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
01380         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01381         $dbman->create_table($table2);
01382 
01383         $DB->insert_record($tablename2, array('course'=>3, 'nametext'=>'badabing'));
01384         $DB->insert_record($tablename2, array('course'=>4, 'nametext'=>'badabang'));
01385         $DB->insert_record($tablename2, array('course'=>5, 'nametext'=>'badabung'));
01386         $DB->insert_record($tablename2, array('course'=>6, 'nametext'=>'badabong'));
01387 
01388         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
01389         $this->assertEqual(2, count($records));
01390         $this->assertEqual($inskey1, reset($records)->id);
01391         $this->assertEqual($inskey4, next($records)->id);
01392 
01393         // Awful test, requires debug enabled and sent to browser. Let's do that and restore after test
01394         $this->enable_debugging();
01395         $records = $DB->get_records_sql("SELECT course AS id, course AS course FROM {{$tablename}}", null);
01396         $this->assertFalse($this->get_debugging() === '');
01397         $this->assertEqual(6, count($records));
01398 
01399         // negative limits = no limits
01400         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, -1, -1);
01401         $this->assertEqual(7, count($records));
01402 
01403         // zero limits = no limits
01404         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 0);
01405         $this->assertEqual(7, count($records));
01406 
01407         // only limitfrom = skips that number of records
01408         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
01409         $this->assertEqual(5, count($records));
01410         $this->assertEqual($inskey3, reset($records)->id);
01411         $this->assertEqual($inskey7, end($records)->id);
01412 
01413         // only limitnum = fetches that number of records
01414         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 3);
01415         $this->assertEqual(3, count($records));
01416         $this->assertEqual($inskey1, reset($records)->id);
01417         $this->assertEqual($inskey3, end($records)->id);
01418 
01419         // both limitfrom and limitnum = skips limitfrom records and fetches limitnum ones
01420         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 3, 2);
01421         $this->assertEqual(2, count($records));
01422         $this->assertEqual($inskey4, reset($records)->id);
01423         $this->assertEqual($inskey5, end($records)->id);
01424 
01425         // both limitfrom and limitnum in query having subqueris
01426         // note the subquery skips records with course = 0 and 3
01427         $sql = "SELECT * FROM {{$tablename}}
01428                  WHERE course NOT IN (
01429                      SELECT course FROM {{$tablename}}
01430                       WHERE course IN (0, 3))
01431                 ORDER BY course";
01432         $records = $DB->get_records_sql($sql, null, 0, 2); // Skip 0, get 2
01433         $this->assertEqual(2, count($records));
01434         $this->assertEqual($inskey6, reset($records)->id);
01435         $this->assertEqual($inskey5, end($records)->id);
01436         $records = $DB->get_records_sql($sql, null, 2, 2); // Skip 2, get 2
01437         $this->assertEqual(2, count($records));
01438         $this->assertEqual($inskey3, reset($records)->id);
01439         $this->assertEqual($inskey2, end($records)->id);
01440 
01441         // test 2 tables with aliases and limits with order bys
01442         $sql = "SELECT t1.id, t1.course AS cid, t2.nametext
01443                   FROM {{$tablename}} t1, {{$tablename2}} t2
01444                  WHERE t2.course=t1.course
01445               ORDER BY t1.course, ". $DB->sql_compare_text('t2.nametext');
01446         $records = $DB->get_records_sql($sql, null, 2, 2); // Skip courses 3 and 6, get 4 and 5
01447         $this->assertEqual(2, count($records));
01448         $this->assertEqual('5', end($records)->cid);
01449         $this->assertEqual('4', reset($records)->cid);
01450 
01451         // test 2 tables with aliases and limits with the highest INT limit works
01452         $records = $DB->get_records_sql($sql, null, 2, PHP_INT_MAX); // Skip course {3,6}, get {4,5}
01453         $this->assertEqual(2, count($records));
01454         $this->assertEqual('5', end($records)->cid);
01455         $this->assertEqual('4', reset($records)->cid);
01456 
01457         // test 2 tables with aliases and limits with order bys (limit which is highest INT number)
01458         $records = $DB->get_records_sql($sql, null, PHP_INT_MAX, 2); // Skip all courses
01459         $this->assertEqual(0, count($records));
01460 
01461         // test 2 tables with aliases and limits with order bys (limit which s highest INT number)
01462         $records = $DB->get_records_sql($sql, null, PHP_INT_MAX, PHP_INT_MAX); // Skip all courses
01463         $this->assertEqual(0, count($records));
01464 
01465         // TODO: Test limits in queries having DISTINCT clauses
01466 
01467         // note: fetching nulls, empties, LOBs already tested by test_update_record() no needed here
01468     }
01469 
01470     public function test_get_records_menu() {
01471         $DB = $this->tdb;
01472         $dbman = $DB->get_manager();
01473 
01474         $table = $this->get_test_table();
01475         $tablename = $table->getName();
01476 
01477         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01478         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01479         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01480         $dbman->create_table($table);
01481 
01482         $DB->insert_record($tablename, array('course' => 3));
01483         $DB->insert_record($tablename, array('course' => 3));
01484         $DB->insert_record($tablename, array('course' => 5));
01485         $DB->insert_record($tablename, array('course' => 2));
01486 
01487         $records = $DB->get_records_menu($tablename, array('course' => 3));
01488         $this->assertTrue(is_array($records));
01489         $this->assertEqual(2, count($records));
01490         $this->assertFalse(empty($records[1]));
01491         $this->assertFalse(empty($records[2]));
01492         $this->assertEqual(3, $records[1]);
01493         $this->assertEqual(3, $records[2]);
01494 
01495         // note: delegate limits testing to test_get_records_sql()
01496     }
01497 
01498     public function test_get_records_select_menu() {
01499         $DB = $this->tdb;
01500         $dbman = $DB->get_manager();
01501 
01502         $table = $this->get_test_table();
01503         $tablename = $table->getName();
01504 
01505         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01506         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01507         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01508         $dbman->create_table($table);
01509 
01510         $DB->insert_record($tablename, array('course' => 3));
01511         $DB->insert_record($tablename, array('course' => 2));
01512         $DB->insert_record($tablename, array('course' => 3));
01513         $DB->insert_record($tablename, array('course' => 5));
01514 
01515         $records = $DB->get_records_select_menu($tablename, "course > ?", array(2));
01516         $this->assertTrue(is_array($records));
01517 
01518         $this->assertEqual(3, count($records));
01519         $this->assertFalse(empty($records[1]));
01520         $this->assertTrue(empty($records[2]));
01521         $this->assertFalse(empty($records[3]));
01522         $this->assertFalse(empty($records[4]));
01523         $this->assertEqual(3, $records[1]);
01524         $this->assertEqual(3, $records[3]);
01525         $this->assertEqual(5, $records[4]);
01526 
01527         // note: delegate limits testing to test_get_records_sql()
01528     }
01529 
01530     public function test_get_records_sql_menu() {
01531         $DB = $this->tdb;
01532         $dbman = $DB->get_manager();
01533 
01534         $table = $this->get_test_table();
01535         $tablename = $table->getName();
01536 
01537         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01538         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01539         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01540         $dbman->create_table($table);
01541 
01542         $DB->insert_record($tablename, array('course' => 3));
01543         $DB->insert_record($tablename, array('course' => 2));
01544         $DB->insert_record($tablename, array('course' => 3));
01545         $DB->insert_record($tablename, array('course' => 5));
01546 
01547         $records = $DB->get_records_sql_menu("SELECT * FROM {{$tablename}} WHERE course > ?", array(2));
01548         $this->assertTrue(is_array($records));
01549 
01550         $this->assertEqual(3, count($records));
01551         $this->assertFalse(empty($records[1]));
01552         $this->assertTrue(empty($records[2]));
01553         $this->assertFalse(empty($records[3]));
01554         $this->assertFalse(empty($records[4]));
01555         $this->assertEqual(3, $records[1]);
01556         $this->assertEqual(3, $records[3]);
01557         $this->assertEqual(5, $records[4]);
01558 
01559         // note: delegate limits testing to test_get_records_sql()
01560     }
01561 
01562     public function test_get_record() {
01563         $DB = $this->tdb;
01564         $dbman = $DB->get_manager();
01565 
01566         $table = $this->get_test_table();
01567         $tablename = $table->getName();
01568 
01569         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01570         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01571         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01572         $dbman->create_table($table);
01573 
01574         $DB->insert_record($tablename, array('course' => 3));
01575         $DB->insert_record($tablename, array('course' => 2));
01576 
01577         $record = $DB->get_record($tablename, array('id' => 2));
01578         $this->assertTrue($record instanceof stdClass);
01579 
01580         $this->assertEqual(2, $record->course);
01581         $this->assertEqual(2, $record->id);
01582     }
01583 
01584 
01585     public function test_get_record_select() {
01586         $DB = $this->tdb;
01587         $dbman = $DB->get_manager();
01588 
01589         $table = $this->get_test_table();
01590         $tablename = $table->getName();
01591 
01592         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01593         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01594         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01595         $dbman->create_table($table);
01596 
01597         $DB->insert_record($tablename, array('course' => 3));
01598         $DB->insert_record($tablename, array('course' => 2));
01599 
01600         $record = $DB->get_record_select($tablename, "id = ?", array(2));
01601         $this->assertTrue($record instanceof stdClass);
01602 
01603         $this->assertEqual(2, $record->course);
01604 
01605         // note: delegates limit testing to test_get_records_sql()
01606     }
01607 
01608     public function test_get_record_sql() {
01609         $DB = $this->tdb;
01610         $dbman = $DB->get_manager();
01611 
01612         $table = $this->get_test_table();
01613         $tablename = $table->getName();
01614 
01615         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01616         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01617         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01618         $dbman->create_table($table);
01619 
01620         $DB->insert_record($tablename, array('course' => 3));
01621         $DB->insert_record($tablename, array('course' => 2));
01622 
01623         // standard use
01624         $record = $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(2));
01625         $this->assertTrue($record instanceof stdClass);
01626         $this->assertEqual(2, $record->course);
01627         $this->assertEqual(2, $record->id);
01628 
01629         // backwards compatibility with $ignoremultiple
01630         $this->assertFalse(IGNORE_MISSING);
01631         $this->assertTrue(IGNORE_MULTIPLE);
01632 
01633         // record not found - ignore
01634         $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MISSING));
01635         $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MULTIPLE));
01636 
01637         // record not found error
01638         try {
01639             $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), MUST_EXIST);
01640             $this->fail("Exception expected");
01641         } catch (dml_missing_record_exception $e) {
01642             $this->assertTrue(true);
01643         }
01644 
01645         $this->enable_debugging();
01646         $this->assertTrue($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MISSING));
01647         $this->assertFalse($this->get_debugging() === '');
01648 
01649         // multiple matches ignored
01650         $this->assertTrue($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MULTIPLE));
01651 
01652         // multiple found error
01653         try {
01654             $DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), MUST_EXIST);
01655             $this->fail("Exception expected");
01656         } catch (dml_multiple_records_exception $e) {
01657             $this->assertTrue(true);
01658         }
01659     }
01660 
01661     public function test_get_field() {
01662         $DB = $this->tdb;
01663         $dbman = $DB->get_manager();
01664 
01665         $table = $this->get_test_table();
01666         $tablename = $table->getName();
01667 
01668         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01669         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01670         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
01671         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01672         $dbman->create_table($table);
01673 
01674         $id1 = $DB->insert_record($tablename, array('course' => 3));
01675         $DB->insert_record($tablename, array('course' => 5));
01676         $DB->insert_record($tablename, array('course' => 5));
01677 
01678         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id1)));
01679         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('course' => 3)));
01680 
01681         $this->assertIdentical(false, $DB->get_field($tablename, 'course', array('course' => 11), IGNORE_MISSING));
01682         try {
01683             $DB->get_field($tablename, 'course', array('course' => 4), MUST_EXIST);
01684             $this->assertFail('Exception expected due to missing record');
01685         } catch (dml_exception $ex) {
01686             $this->assertTrue(true);
01687         }
01688 
01689         $this->enable_debugging();
01690         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MULTIPLE));
01691         $this->assertIdentical($this->get_debugging(), '');
01692 
01693         $this->enable_debugging();
01694         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MISSING));
01695         $this->assertFalse($this->get_debugging() === '');
01696 
01697         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
01698         $conditions = array('onetext' => '1');
01699         try {
01700             $DB->get_field($tablename, 'course', $conditions);
01701             if (debugging()) {
01702                 // only in debug mode - hopefully all devs test code in debug mode...
01703                 $this->fail('An Exception is missing, expected due to equating of text fields');
01704             }
01705         } catch (exception $e) {
01706             $this->assertTrue($e instanceof dml_exception);
01707             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
01708         }
01709     }
01710 
01711     public function test_get_field_select() {
01712         $DB = $this->tdb;
01713         $dbman = $DB->get_manager();
01714 
01715         $table = $this->get_test_table();
01716         $tablename = $table->getName();
01717 
01718         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01719         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01720         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01721         $dbman->create_table($table);
01722 
01723         $DB->insert_record($tablename, array('course' => 3));
01724 
01725         $this->assertEqual(3, $DB->get_field_select($tablename, 'course', "id = ?", array(1)));
01726     }
01727 
01728     public function test_get_field_sql() {
01729         $DB = $this->tdb;
01730         $dbman = $DB->get_manager();
01731 
01732         $table = $this->get_test_table();
01733         $tablename = $table->getName();
01734 
01735         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01736         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01737         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01738         $dbman->create_table($table);
01739 
01740         $DB->insert_record($tablename, array('course' => 3));
01741 
01742         $this->assertEqual(3, $DB->get_field_sql("SELECT course FROM {{$tablename}} WHERE id = ?", array(1)));
01743     }
01744 
01745     public function test_get_fieldset_select() {
01746         $DB = $this->tdb;
01747         $dbman = $DB->get_manager();
01748 
01749         $table = $this->get_test_table();
01750         $tablename = $table->getName();
01751 
01752         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01753         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01754         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01755         $dbman->create_table($table);
01756 
01757         $DB->insert_record($tablename, array('course' => 1));
01758         $DB->insert_record($tablename, array('course' => 3));
01759         $DB->insert_record($tablename, array('course' => 2));
01760         $DB->insert_record($tablename, array('course' => 6));
01761 
01762         $fieldset = $DB->get_fieldset_select($tablename, 'course', "course > ?", array(1));
01763         $this->assertTrue(is_array($fieldset));
01764 
01765         $this->assertEqual(3, count($fieldset));
01766         $this->assertEqual(3, $fieldset[0]);
01767         $this->assertEqual(2, $fieldset[1]);
01768         $this->assertEqual(6, $fieldset[2]);
01769     }
01770 
01771     public function test_get_fieldset_sql() {
01772         $DB = $this->tdb;
01773         $dbman = $DB->get_manager();
01774 
01775         $table = $this->get_test_table();
01776         $tablename = $table->getName();
01777 
01778         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01779         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01780         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01781         $dbman->create_table($table);
01782 
01783         $DB->insert_record($tablename, array('course' => 1));
01784         $DB->insert_record($tablename, array('course' => 3));
01785         $DB->insert_record($tablename, array('course' => 2));
01786         $DB->insert_record($tablename, array('course' => 6));
01787 
01788         $fieldset = $DB->get_fieldset_sql("SELECT * FROM {{$tablename}} WHERE course > ?", array(1));
01789         $this->assertTrue(is_array($fieldset));
01790 
01791         $this->assertEqual(3, count($fieldset));
01792         $this->assertEqual(2, $fieldset[0]);
01793         $this->assertEqual(3, $fieldset[1]);
01794         $this->assertEqual(4, $fieldset[2]);
01795     }
01796 
01797     public function test_insert_record_raw() {
01798         $DB = $this->tdb;
01799         $dbman = $DB->get_manager();
01800 
01801         $table = $this->get_test_table();
01802         $tablename = $table->getName();
01803 
01804         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01805         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01806         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
01807         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01808         $dbman->create_table($table);
01809 
01810         $record = (object)array('course' => 1, 'onechar' => 'xx');
01811         $before = clone($record);
01812         $result = $DB->insert_record_raw($tablename, $record);
01813         $this->assertIdentical(1, $result);
01814         $this->assertIdentical($record, $before);
01815 
01816         $record = $DB->get_record($tablename, array('course' => 1));
01817         $this->assertTrue($record instanceof stdClass);
01818         $this->assertIdentical('xx', $record->onechar);
01819 
01820         $result = $DB->insert_record_raw($tablename, array('course' => 2, 'onechar' => 'yy'), false);
01821         $this->assertIdentical(true, $result);
01822 
01823         // note: bulk not implemented yet
01824         $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'zz'), true, true);
01825         $record = $DB->get_record($tablename, array('course' => 3));
01826         $this->assertTrue($record instanceof stdClass);
01827         $this->assertIdentical('zz', $record->onechar);
01828 
01829         // custom sequence (id) - returnid is ignored
01830         $result = $DB->insert_record_raw($tablename, array('id' => 10, 'course' => 3, 'onechar' => 'bb'), true, false, true);
01831         $this->assertIdentical(true, $result);
01832         $record = $DB->get_record($tablename, array('id' => 10));
01833         $this->assertTrue($record instanceof stdClass);
01834         $this->assertIdentical('bb', $record->onechar);
01835 
01836         // custom sequence - missing id error
01837         try {
01838             $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'bb'), true, false, true);
01839             $this->assertFail('Exception expected due to missing record');
01840         } catch (coding_exception $ex) {
01841             $this->assertTrue(true);
01842         }
01843 
01844         // wrong column error
01845         try {
01846             $DB->insert_record_raw($tablename, array('xxxxx' => 3, 'onechar' => 'bb'));
01847             $this->assertFail('Exception expected due to invalid column');
01848         } catch (dml_exception $ex) {
01849             $this->assertTrue(true);
01850         }
01851     }
01852 
01853     public function test_insert_record() {
01854         // All the information in this test is fetched from DB by get_recordset() so we
01855         // have such method properly tested against nulls, empties and friends...
01856 
01857         $DB = $this->tdb;
01858         $dbman = $DB->get_manager();
01859 
01860         $table = $this->get_test_table();
01861         $tablename = $table->getName();
01862 
01863         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
01864         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
01865         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
01866         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
01867         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
01868         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
01869         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
01870         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
01871         $dbman->create_table($table);
01872 
01873         $this->assertIdentical(1, $DB->insert_record($tablename, array('course' => 1), true));
01874         $record = $DB->get_record($tablename, array('course' => 1));
01875         $this->assertEqual(1, $record->id);
01876         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
01877         $this->assertEqual(200, $record->onenum);
01878         $this->assertIdentical('onestring', $record->onechar);
01879         $this->assertNull($record->onetext);
01880         $this->assertNull($record->onebinary);
01881 
01882         // without returning id, bulk not implemented
01883         $result = $this->assertIdentical(true, $DB->insert_record($tablename, array('course' => 99), false, true));
01884         $record = $DB->get_record($tablename, array('course' => 99));
01885         $this->assertEqual(2, $record->id);
01886         $this->assertEqual(99, $record->course);
01887 
01888         // Check nulls are set properly for all types
01889         $record = new stdClass();
01890         $record->oneint = null;
01891         $record->onenum = null;
01892         $record->onechar = null;
01893         $record->onetext = null;
01894         $record->onebinary = null;
01895         $recid = $DB->insert_record($tablename, $record);
01896         $record = $DB->get_record($tablename, array('id' => $recid));
01897         $this->assertEqual(0, $record->course);
01898         $this->assertNull($record->oneint);
01899         $this->assertNull($record->onenum);
01900         $this->assertNull($record->onechar);
01901         $this->assertNull($record->onetext);
01902         $this->assertNull($record->onebinary);
01903 
01904         // Check zeros are set properly for all types
01905         $record = new stdClass();
01906         $record->oneint = 0;
01907         $record->onenum = 0;
01908         $recid = $DB->insert_record($tablename, $record);
01909         $record = $DB->get_record($tablename, array('id' => $recid));
01910         $this->assertEqual(0, $record->oneint);
01911         $this->assertEqual(0, $record->onenum);
01912 
01913         // Check booleans are set properly for all types
01914         $record = new stdClass();
01915         $record->oneint = true; // trues
01916         $record->onenum = true;
01917         $record->onechar = true;
01918         $record->onetext = true;
01919         $recid = $DB->insert_record($tablename, $record);
01920         $record = $DB->get_record($tablename, array('id' => $recid));
01921         $this->assertEqual(1, $record->oneint);
01922         $this->assertEqual(1, $record->onenum);
01923         $this->assertEqual(1, $record->onechar);
01924         $this->assertEqual(1, $record->onetext);
01925 
01926         $record = new stdClass();
01927         $record->oneint = false; // falses
01928         $record->onenum = false;
01929         $record->onechar = false;
01930         $record->onetext = false;
01931         $recid = $DB->insert_record($tablename, $record);
01932         $record = $DB->get_record($tablename, array('id' => $recid));
01933         $this->assertEqual(0, $record->oneint);
01934         $this->assertEqual(0, $record->onenum);
01935         $this->assertEqual(0, $record->onechar);
01936         $this->assertEqual(0, $record->onetext);
01937 
01938         // Check string data causes exception in numeric types
01939         $record = new stdClass();
01940         $record->oneint = 'onestring';
01941         $record->onenum = 0;
01942         try {
01943             $DB->insert_record($tablename, $record);
01944             $this->fail("Expecting an exception, none occurred");
01945         } catch (exception $e) {
01946             $this->assertTrue($e instanceof dml_exception);
01947         }
01948         $record = new stdClass();
01949         $record->oneint = 0;
01950         $record->onenum = 'onestring';
01951         try {
01952            $DB->insert_record($tablename, $record);
01953            $this->fail("Expecting an exception, none occurred");
01954         } catch (exception $e) {
01955             $this->assertTrue($e instanceof dml_exception);
01956         }
01957 
01958         // Check empty string data is stored as 0 in numeric datatypes
01959         $record = new stdClass();
01960         $record->oneint = ''; // empty string
01961         $record->onenum = 0;
01962         $recid = $DB->insert_record($tablename, $record);
01963         $record = $DB->get_record($tablename, array('id' => $recid));
01964         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
01965 
01966         $record = new stdClass();
01967         $record->oneint = 0;
01968         $record->onenum = ''; // empty string
01969         $recid = $DB->insert_record($tablename, $record);
01970         $record = $DB->get_record($tablename, array('id' => $recid));
01971         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
01972 
01973         // Check empty strings are set properly in string types
01974         $record = new stdClass();
01975         $record->oneint = 0;
01976         $record->onenum = 0;
01977         $record->onechar = '';
01978         $record->onetext = '';
01979         $recid = $DB->insert_record($tablename, $record);
01980         $record = $DB->get_record($tablename, array('id' => $recid));
01981         $this->assertTrue($record->onechar === '');
01982         $this->assertTrue($record->onetext === '');
01983 
01984         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
01985         $record = new stdClass();
01986         $record->oneint = ((210.10 + 39.92) - 150.02);
01987         $record->onenum = ((210.10 + 39.92) - 150.02);
01988         $recid = $DB->insert_record($tablename, $record);
01989         $record = $DB->get_record($tablename, array('id' => $recid));
01990         $this->assertEqual(100, $record->oneint);
01991         $this->assertEqual(100, $record->onenum);
01992 
01993         // Check various quotes/backslashes combinations in string types
01994         $teststrings = array(
01995             'backslashes and quotes alone (even): "" \'\' \\\\',
01996             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
01997             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
01998             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
01999         foreach ($teststrings as $teststring) {
02000             $record = new stdClass();
02001             $record->onechar = $teststring;
02002             $record->onetext = $teststring;
02003             $recid = $DB->insert_record($tablename, $record);
02004             $record = $DB->get_record($tablename, array('id' => $recid));
02005             $this->assertEqual($teststring, $record->onechar);
02006             $this->assertEqual($teststring, $record->onetext);
02007         }
02008 
02009         // Check LOBs in text/binary columns
02010         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
02011         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
02012         $record = new stdClass();
02013         $record->onetext = $clob;
02014         $record->onebinary = $blob;
02015         $recid = $DB->insert_record($tablename, $record);
02016         $rs = $DB->get_recordset($tablename, array('id' => $recid));
02017         $record = $rs->current();
02018         $rs->close();
02019         $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
02020         $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
02021 
02022         // And "small" LOBs too, just in case
02023         $newclob = substr($clob, 0, 500);
02024         $newblob = substr($blob, 0, 250);
02025         $record = new stdClass();
02026         $record->onetext = $newclob;
02027         $record->onebinary = $newblob;
02028         $recid = $DB->insert_record($tablename, $record);
02029         $rs = $DB->get_recordset($tablename, array('id' => $recid));
02030         $record = $rs->current();
02031         $rs->close();
02032         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
02033         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
02034         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
02035 
02036         // And "diagnostic" LOBs too, just in case
02037         $newclob = '\'"\\;/ěščřžýáíé';
02038         $newblob = '\'"\\;/ěščřžýáíé';
02039         $record = new stdClass();
02040         $record->onetext = $newclob;
02041         $record->onebinary = $newblob;
02042         $recid = $DB->insert_record($tablename, $record);
02043         $rs = $DB->get_recordset($tablename, array('id' => $recid));
02044         $record = $rs->current();
02045         $rs->close();
02046         $this->assertIdentical($newclob, $record->onetext);
02047         $this->assertIdentical($newblob, $record->onebinary);
02048         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
02049 
02050         // test data is not modified
02051         $record = new stdClass();
02052         $record->id     = -1; // has to be ignored
02053         $record->course = 3;
02054         $record->lalala = 'lalal'; // unused
02055         $before = clone($record);
02056         $DB->insert_record($tablename, $record);
02057         $this->assertEqual($record, $before);
02058 
02059         // make sure the id is always increasing and never reuses the same id
02060         $id1 = $DB->insert_record($tablename, array('course' => 3));
02061         $id2 = $DB->insert_record($tablename, array('course' => 3));
02062         $this->assertTrue($id1 < $id2);
02063         $DB->delete_records($tablename, array('id'=>$id2));
02064         $id3 = $DB->insert_record($tablename, array('course' => 3));
02065         $this->assertTrue($id2 < $id3);
02066         $DB->delete_records($tablename, array());
02067         $id4 = $DB->insert_record($tablename, array('course' => 3));
02068         $this->assertTrue($id3 < $id4);
02069 
02070         // Test saving a float in a CHAR column, and reading it back.
02071         $id = $DB->insert_record($tablename, array('onechar' => 1.0));
02072         $this->assertEqual(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02073         $id = $DB->insert_record($tablename, array('onechar' => 1e20));
02074         $this->assertEqual(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02075         $id = $DB->insert_record($tablename, array('onechar' => 1e-4));
02076         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02077         $id = $DB->insert_record($tablename, array('onechar' => 1e-5));
02078         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02079         $id = $DB->insert_record($tablename, array('onechar' => 1e-300));
02080         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02081         $id = $DB->insert_record($tablename, array('onechar' => 1e300));
02082         $this->assertEqual(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02083 
02084         // Test saving a float in a TEXT column, and reading it back.
02085         $id = $DB->insert_record($tablename, array('onetext' => 1.0));
02086         $this->assertEqual(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02087         $id = $DB->insert_record($tablename, array('onetext' => 1e20));
02088         $this->assertEqual(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02089         $id = $DB->insert_record($tablename, array('onetext' => 1e-4));
02090         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02091         $id = $DB->insert_record($tablename, array('onetext' => 1e-5));
02092         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02093         $id = $DB->insert_record($tablename, array('onetext' => 1e-300));
02094         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02095         $id = $DB->insert_record($tablename, array('onetext' => 1e300));
02096         $this->assertEqual(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02097     }
02098 
02099     public function test_import_record() {
02100         // All the information in this test is fetched from DB by get_recordset() so we
02101         // have such method properly tested against nulls, empties and friends...
02102 
02103         $DB = $this->tdb;
02104         $dbman = $DB->get_manager();
02105 
02106         $table = $this->get_test_table();
02107         $tablename = $table->getName();
02108 
02109         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02110         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02111         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
02112         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
02113         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
02114         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
02115         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
02116         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02117         $dbman->create_table($table);
02118 
02119         $this->assertIdentical(1, $DB->insert_record($tablename, array('course' => 1), true));
02120         $record = $DB->get_record($tablename, array('course' => 1));
02121         $this->assertEqual(1, $record->id);
02122         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
02123         $this->assertEqual(200, $record->onenum);
02124         $this->assertIdentical('onestring', $record->onechar);
02125         $this->assertNull($record->onetext);
02126         $this->assertNull($record->onebinary);
02127 
02128         // ignore extra columns
02129         $record = (object)array('id'=>13, 'course'=>2, 'xxxx'=>788778);
02130         $before = clone($record);
02131         $this->assertIdentical(true, $DB->import_record($tablename, $record));
02132         $this->assertIdentical($record, $before);
02133         $records = $DB->get_records($tablename);
02134         $this->assertEqual(2, $records[13]->course);
02135 
02136         // Check nulls are set properly for all types
02137         $record = new stdClass();
02138         $record->id = 20;
02139         $record->oneint = null;
02140         $record->onenum = null;
02141         $record->onechar = null;
02142         $record->onetext = null;
02143         $record->onebinary = null;
02144         $this->assertTrue($DB->import_record($tablename, $record));
02145         $record = $DB->get_record($tablename, array('id' => 20));
02146         $this->assertEqual(0, $record->course);
02147         $this->assertNull($record->oneint);
02148         $this->assertNull($record->onenum);
02149         $this->assertNull($record->onechar);
02150         $this->assertNull($record->onetext);
02151         $this->assertNull($record->onebinary);
02152 
02153         // Check zeros are set properly for all types
02154         $record = new stdClass();
02155         $record->id = 23;
02156         $record->oneint = 0;
02157         $record->onenum = 0;
02158         $this->assertTrue($DB->import_record($tablename, $record));
02159         $record = $DB->get_record($tablename, array('id' => 23));
02160         $this->assertEqual(0, $record->oneint);
02161         $this->assertEqual(0, $record->onenum);
02162 
02163         // Check string data causes exception in numeric types
02164         $record = new stdClass();
02165         $record->id = 32;
02166         $record->oneint = 'onestring';
02167         $record->onenum = 0;
02168         try {
02169             $DB->import_record($tablename, $record);
02170             $this->fail("Expecting an exception, none occurred");
02171         } catch (exception $e) {
02172             $this->assertTrue($e instanceof dml_exception);
02173         }
02174         $record = new stdClass();
02175         $record->id = 35;
02176         $record->oneint = 0;
02177         $record->onenum = 'onestring';
02178         try {
02179            $DB->import_record($tablename, $record);
02180            $this->fail("Expecting an exception, none occurred");
02181         } catch (exception $e) {
02182             $this->assertTrue($e instanceof dml_exception);
02183         }
02184 
02185         // Check empty strings are set properly in string types
02186         $record = new stdClass();
02187         $record->id = 44;
02188         $record->oneint = 0;
02189         $record->onenum = 0;
02190         $record->onechar = '';
02191         $record->onetext = '';
02192         $this->assertTrue($DB->import_record($tablename, $record));
02193         $record = $DB->get_record($tablename, array('id' => 44));
02194         $this->assertTrue($record->onechar === '');
02195         $this->assertTrue($record->onetext === '');
02196 
02197         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
02198         $record = new stdClass();
02199         $record->id = 47;
02200         $record->oneint = ((210.10 + 39.92) - 150.02);
02201         $record->onenum = ((210.10 + 39.92) - 150.02);
02202         $this->assertTrue($DB->import_record($tablename, $record));
02203         $record = $DB->get_record($tablename, array('id' => 47));
02204         $this->assertEqual(100, $record->oneint);
02205         $this->assertEqual(100, $record->onenum);
02206 
02207         // Check various quotes/backslashes combinations in string types
02208         $i = 50;
02209         $teststrings = array(
02210             'backslashes and quotes alone (even): "" \'\' \\\\',
02211             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
02212             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
02213             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
02214         foreach ($teststrings as $teststring) {
02215             $record = new stdClass();
02216             $record->id = $i;
02217             $record->onechar = $teststring;
02218             $record->onetext = $teststring;
02219             $this->assertTrue($DB->import_record($tablename, $record));
02220             $record = $DB->get_record($tablename, array('id' => $i));
02221             $this->assertEqual($teststring, $record->onechar);
02222             $this->assertEqual($teststring, $record->onetext);
02223             $i = $i + 3;
02224         }
02225 
02226         // Check LOBs in text/binary columns
02227         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
02228         $record = new stdClass();
02229         $record->id = 70;
02230         $record->onetext = $clob;
02231         $record->onebinary = '';
02232         $this->assertTrue($DB->import_record($tablename, $record));
02233         $rs = $DB->get_recordset($tablename, array('id' => 70));
02234         $record = $rs->current();
02235         $rs->close();
02236         $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
02237 
02238         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
02239         $record = new stdClass();
02240         $record->id = 71;
02241         $record->onetext = '';
02242         $record->onebinary = $blob;
02243         $this->assertTrue($DB->import_record($tablename, $record));
02244         $rs = $DB->get_recordset($tablename, array('id' => 71));
02245         $record = $rs->current();
02246         $rs->close();
02247         $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
02248 
02249         // And "small" LOBs too, just in case
02250         $newclob = substr($clob, 0, 500);
02251         $newblob = substr($blob, 0, 250);
02252         $record = new stdClass();
02253         $record->id = 73;
02254         $record->onetext = $newclob;
02255         $record->onebinary = $newblob;
02256         $this->assertTrue($DB->import_record($tablename, $record));
02257         $rs = $DB->get_recordset($tablename, array('id' => 73));
02258         $record = $rs->current();
02259         $rs->close();
02260         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
02261         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
02262         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
02263     }
02264 
02265     public function test_update_record_raw() {
02266         $DB = $this->tdb;
02267         $dbman = $DB->get_manager();
02268 
02269         $table = $this->get_test_table();
02270         $tablename = $table->getName();
02271 
02272         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02273         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02274         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02275         $dbman->create_table($table);
02276 
02277         $DB->insert_record($tablename, array('course' => 1));
02278         $DB->insert_record($tablename, array('course' => 3));
02279 
02280         $record = $DB->get_record($tablename, array('course' => 1));
02281         $record->course = 2;
02282         $this->assertTrue($DB->update_record_raw($tablename, $record));
02283         $this->assertEqual(0, $DB->count_records($tablename, array('course' => 1)));
02284         $this->assertEqual(1, $DB->count_records($tablename, array('course' => 2)));
02285         $this->assertEqual(1, $DB->count_records($tablename, array('course' => 3)));
02286 
02287         $record = $DB->get_record($tablename, array('course' => 1));
02288         $record->xxxxx = 2;
02289         try {
02290            $DB->update_record_raw($tablename, $record);
02291            $this->fail("Expecting an exception, none occurred");
02292         } catch (Exception $e) {
02293             $this->assertTrue($e instanceof coding_exception);
02294         }
02295 
02296         $record = $DB->get_record($tablename, array('course' => 3));
02297         unset($record->id);
02298         try {
02299            $DB->update_record_raw($tablename, $record);
02300            $this->fail("Expecting an exception, none occurred");
02301         } catch (Exception $e) {
02302             $this->assertTrue($e instanceof coding_exception);
02303         }
02304     }
02305 
02306     public function test_update_record() {
02307 
02308         // All the information in this test is fetched from DB by get_record() so we
02309         // have such method properly tested against nulls, empties and friends...
02310 
02311         $DB = $this->tdb;
02312         $dbman = $DB->get_manager();
02313 
02314         $table = $this->get_test_table();
02315         $tablename = $table->getName();
02316 
02317         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02318         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02319         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
02320         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
02321         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
02322         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
02323         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
02324         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02325         $dbman->create_table($table);
02326 
02327         $DB->insert_record($tablename, array('course' => 1));
02328         $record = $DB->get_record($tablename, array('course' => 1));
02329         $record->course = 2;
02330 
02331         $this->assertTrue($DB->update_record($tablename, $record));
02332         $this->assertFalse($record = $DB->get_record($tablename, array('course' => 1)));
02333         $this->assertTrue($record = $DB->get_record($tablename, array('course' => 2)));
02334         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
02335         $this->assertEqual(200, $record->onenum);
02336         $this->assertEqual('onestring', $record->onechar);
02337         $this->assertNull($record->onetext);
02338         $this->assertNull($record->onebinary);
02339 
02340         // Check nulls are set properly for all types
02341         $record->oneint = null;
02342         $record->onenum = null;
02343         $record->onechar = null;
02344         $record->onetext = null;
02345         $record->onebinary = null;
02346         $DB->update_record($tablename, $record);
02347         $record = $DB->get_record($tablename, array('course' => 2));
02348         $this->assertNull($record->oneint);
02349         $this->assertNull($record->onenum);
02350         $this->assertNull($record->onechar);
02351         $this->assertNull($record->onetext);
02352         $this->assertNull($record->onebinary);
02353 
02354         // Check zeros are set properly for all types
02355         $record->oneint = 0;
02356         $record->onenum = 0;
02357         $DB->update_record($tablename, $record);
02358         $record = $DB->get_record($tablename, array('course' => 2));
02359         $this->assertEqual(0, $record->oneint);
02360         $this->assertEqual(0, $record->onenum);
02361 
02362         // Check booleans are set properly for all types
02363         $record->oneint = true; // trues
02364         $record->onenum = true;
02365         $record->onechar = true;
02366         $record->onetext = true;
02367         $DB->update_record($tablename, $record);
02368         $record = $DB->get_record($tablename, array('course' => 2));
02369         $this->assertEqual(1, $record->oneint);
02370         $this->assertEqual(1, $record->onenum);
02371         $this->assertEqual(1, $record->onechar);
02372         $this->assertEqual(1, $record->onetext);
02373 
02374         $record->oneint = false; // falses
02375         $record->onenum = false;
02376         $record->onechar = false;
02377         $record->onetext = false;
02378         $DB->update_record($tablename, $record);
02379         $record = $DB->get_record($tablename, array('course' => 2));
02380         $this->assertEqual(0, $record->oneint);
02381         $this->assertEqual(0, $record->onenum);
02382         $this->assertEqual(0, $record->onechar);
02383         $this->assertEqual(0, $record->onetext);
02384 
02385         // Check string data causes exception in numeric types
02386         $record->oneint = 'onestring';
02387         $record->onenum = 0;
02388         try {
02389             $DB->update_record($tablename, $record);
02390             $this->fail("Expecting an exception, none occurred");
02391         } catch (exception $e) {
02392             $this->assertTrue($e instanceof dml_exception);
02393         }
02394         $record->oneint = 0;
02395         $record->onenum = 'onestring';
02396         try {
02397             $DB->update_record($tablename, $record);
02398             $this->fail("Expecting an exception, none occurred");
02399         } catch (exception $e) {
02400             $this->assertTrue($e instanceof dml_exception);
02401         }
02402 
02403         // Check empty string data is stored as 0 in numeric datatypes
02404         $record->oneint = ''; // empty string
02405         $record->onenum = 0;
02406         $DB->update_record($tablename, $record);
02407         $record = $DB->get_record($tablename, array('course' => 2));
02408         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
02409 
02410         $record->oneint = 0;
02411         $record->onenum = ''; // empty string
02412         $DB->update_record($tablename, $record);
02413         $record = $DB->get_record($tablename, array('course' => 2));
02414         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
02415 
02416         // Check empty strings are set properly in string types
02417         $record->oneint = 0;
02418         $record->onenum = 0;
02419         $record->onechar = '';
02420         $record->onetext = '';
02421         $DB->update_record($tablename, $record);
02422         $record = $DB->get_record($tablename, array('course' => 2));
02423         $this->assertTrue($record->onechar === '');
02424         $this->assertTrue($record->onetext === '');
02425 
02426         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
02427         $record->oneint = ((210.10 + 39.92) - 150.02);
02428         $record->onenum = ((210.10 + 39.92) - 150.02);
02429         $DB->update_record($tablename, $record);
02430         $record = $DB->get_record($tablename, array('course' => 2));
02431         $this->assertEqual(100, $record->oneint);
02432         $this->assertEqual(100, $record->onenum);
02433 
02434         // Check various quotes/backslashes combinations in string types
02435         $teststrings = array(
02436             'backslashes and quotes alone (even): "" \'\' \\\\',
02437             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
02438             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
02439             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
02440         foreach ($teststrings as $teststring) {
02441             $record->onechar = $teststring;
02442             $record->onetext = $teststring;
02443             $DB->update_record($tablename, $record);
02444             $record = $DB->get_record($tablename, array('course' => 2));
02445             $this->assertEqual($teststring, $record->onechar);
02446             $this->assertEqual($teststring, $record->onetext);
02447         }
02448 
02449         // Check LOBs in text/binary columns
02450         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
02451         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
02452         $record->onetext = $clob;
02453         $record->onebinary = $blob;
02454         $DB->update_record($tablename, $record);
02455         $record = $DB->get_record($tablename, array('course' => 2));
02456         $this->assertEqual($clob, $record->onetext, 'Test CLOB update (full contents output disabled)');
02457         $this->assertEqual($blob, $record->onebinary, 'Test BLOB update (full contents output disabled)');
02458 
02459         // And "small" LOBs too, just in case
02460         $newclob = substr($clob, 0, 500);
02461         $newblob = substr($blob, 0, 250);
02462         $record->onetext = $newclob;
02463         $record->onebinary = $newblob;
02464         $DB->update_record($tablename, $record);
02465         $record = $DB->get_record($tablename, array('course' => 2));
02466         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB update (full contents output disabled)');
02467         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB update (full contents output disabled)');
02468 
02469         // Test saving a float in a CHAR column, and reading it back.
02470         $id = $DB->insert_record($tablename, array('onechar' => 'X'));
02471         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1.0));
02472         $this->assertEqual(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02473         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e20));
02474         $this->assertEqual(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02475         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-4));
02476         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02477         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-5));
02478         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02479         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-300));
02480         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02481         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e300));
02482         $this->assertEqual(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02483 
02484         // Test saving a float in a TEXT column, and reading it back.
02485         $id = $DB->insert_record($tablename, array('onetext' => 'X'));
02486         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1.0));
02487         $this->assertEqual(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02488         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e20));
02489         $this->assertEqual(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02490         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-4));
02491         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02492         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-5));
02493         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02494         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-300));
02495         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02496         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e300));
02497         $this->assertEqual(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02498     }
02499 
02500     public function test_set_field() {
02501         $DB = $this->tdb;
02502         $dbman = $DB->get_manager();
02503 
02504         $table = $this->get_test_table();
02505         $tablename = $table->getName();
02506 
02507         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02508         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02509         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
02510         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
02511         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02512         $dbman->create_table($table);
02513 
02514         // simple set_field
02515         $id1 = $DB->insert_record($tablename, array('course' => 1));
02516         $id2 = $DB->insert_record($tablename, array('course' => 1));
02517         $id3 = $DB->insert_record($tablename, array('course' => 3));
02518         $this->assertTrue($DB->set_field($tablename, 'course', 2, array('id' => $id1)));
02519         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => $id1)));
02520         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
02521         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
02522         $DB->delete_records($tablename, array());
02523 
02524         // multiple fields affected
02525         $id1 = $DB->insert_record($tablename, array('course' => 1));
02526         $id2 = $DB->insert_record($tablename, array('course' => 1));
02527         $id3 = $DB->insert_record($tablename, array('course' => 3));
02528         $DB->set_field($tablename, 'course', '5', array('course' => 1));
02529         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
02530         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
02531         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
02532         $DB->delete_records($tablename, array());
02533 
02534         // no field affected
02535         $id1 = $DB->insert_record($tablename, array('course' => 1));
02536         $id2 = $DB->insert_record($tablename, array('course' => 1));
02537         $id3 = $DB->insert_record($tablename, array('course' => 3));
02538         $DB->set_field($tablename, 'course', '5', array('course' => 0));
02539         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id1)));
02540         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
02541         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
02542         $DB->delete_records($tablename, array());
02543 
02544         // all fields - no condition
02545         $id1 = $DB->insert_record($tablename, array('course' => 1));
02546         $id2 = $DB->insert_record($tablename, array('course' => 1));
02547         $id3 = $DB->insert_record($tablename, array('course' => 3));
02548         $DB->set_field($tablename, 'course', 5, array());
02549         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
02550         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
02551         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id3)));
02552 
02553         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
02554         $conditions = array('onetext' => '1');
02555         try {
02556             $DB->set_field($tablename, 'onechar', 'frog', $conditions);
02557             if (debugging()) {
02558                 // only in debug mode - hopefully all devs test code in debug mode...
02559                 $this->fail('An Exception is missing, expected due to equating of text fields');
02560             }
02561         } catch (exception $e) {
02562             $this->assertTrue($e instanceof dml_exception);
02563             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
02564         }
02565 
02566         // Test saving a float in a CHAR column, and reading it back.
02567         $id = $DB->insert_record($tablename, array('onechar' => 'X'));
02568         $DB->set_field($tablename, 'onechar', 1.0, array('id' => $id));
02569         $this->assertEqual(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02570         $DB->set_field($tablename, 'onechar', 1e20, array('id' => $id));
02571         $this->assertEqual(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02572         $DB->set_field($tablename, 'onechar', 1e-4, array('id' => $id));
02573         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02574         $DB->set_field($tablename, 'onechar', 1e-5, array('id' => $id));
02575         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02576         $DB->set_field($tablename, 'onechar', 1e-300, array('id' => $id));
02577         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02578         $DB->set_field($tablename, 'onechar', 1e300, array('id' => $id));
02579         $this->assertEqual(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
02580 
02581         // Test saving a float in a TEXT column, and reading it back.
02582         $id = $DB->insert_record($tablename, array('onetext' => 'X'));
02583         $DB->set_field($tablename, 'onetext', 1.0, array('id' => $id));
02584         $this->assertEqual(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02585         $DB->set_field($tablename, 'onetext', 1e20, array('id' => $id));
02586         $this->assertEqual(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02587         $DB->set_field($tablename, 'onetext', 1e-4, array('id' => $id));
02588         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02589         $DB->set_field($tablename, 'onetext', 1e-5, array('id' => $id));
02590         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02591         $DB->set_field($tablename, 'onetext', 1e-300, array('id' => $id));
02592         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02593         $DB->set_field($tablename, 'onetext', 1e300, array('id' => $id));
02594         $this->assertEqual(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
02595 
02596         // Note: All the nulls, booleans, empties, quoted and backslashes tests
02597         // go to set_field_select() because set_field() is just one wrapper over it
02598     }
02599 
02600     public function test_set_field_select() {
02601 
02602         // All the information in this test is fetched from DB by get_field() so we
02603         // have such method properly tested against nulls, empties and friends...
02604 
02605         $DB = $this->tdb;
02606         $dbman = $DB->get_manager();
02607 
02608         $table = $this->get_test_table();
02609         $tablename = $table->getName();
02610 
02611         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02612         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02613         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null);
02614         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null);
02615         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
02616         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
02617         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
02618         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02619         $dbman->create_table($table);
02620 
02621         $DB->insert_record($tablename, array('course' => 1));
02622 
02623         $this->assertTrue($DB->set_field_select($tablename, 'course', 2, 'id = ?', array(1)));
02624         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => 1)));
02625 
02626         // Check nulls are set properly for all types
02627         $DB->set_field_select($tablename, 'oneint', null, 'id = ?', array(1)); // trues
02628         $DB->set_field_select($tablename, 'onenum', null, 'id = ?', array(1));
02629         $DB->set_field_select($tablename, 'onechar', null, 'id = ?', array(1));
02630         $DB->set_field_select($tablename, 'onetext', null, 'id = ?', array(1));
02631         $DB->set_field_select($tablename, 'onebinary', null, 'id = ?', array(1));
02632         $this->assertNull($DB->get_field($tablename, 'oneint', array('id' => 1)));
02633         $this->assertNull($DB->get_field($tablename, 'onenum', array('id' => 1)));
02634         $this->assertNull($DB->get_field($tablename, 'onechar', array('id' => 1)));
02635         $this->assertNull($DB->get_field($tablename, 'onetext', array('id' => 1)));
02636         $this->assertNull($DB->get_field($tablename, 'onebinary', array('id' => 1)));
02637 
02638         // Check zeros are set properly for all types
02639         $DB->set_field_select($tablename, 'oneint', 0, 'id = ?', array(1));
02640         $DB->set_field_select($tablename, 'onenum', 0, 'id = ?', array(1));
02641         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
02642         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
02643 
02644         // Check booleans are set properly for all types
02645         $DB->set_field_select($tablename, 'oneint', true, 'id = ?', array(1)); // trues
02646         $DB->set_field_select($tablename, 'onenum', true, 'id = ?', array(1));
02647         $DB->set_field_select($tablename, 'onechar', true, 'id = ?', array(1));
02648         $DB->set_field_select($tablename, 'onetext', true, 'id = ?', array(1));
02649         $this->assertEqual(1, $DB->get_field($tablename, 'oneint', array('id' => 1)));
02650         $this->assertEqual(1, $DB->get_field($tablename, 'onenum', array('id' => 1)));
02651         $this->assertEqual(1, $DB->get_field($tablename, 'onechar', array('id' => 1)));
02652         $this->assertEqual(1, $DB->get_field($tablename, 'onetext', array('id' => 1)));
02653 
02654         $DB->set_field_select($tablename, 'oneint', false, 'id = ?', array(1)); // falses
02655         $DB->set_field_select($tablename, 'onenum', false, 'id = ?', array(1));
02656         $DB->set_field_select($tablename, 'onechar', false, 'id = ?', array(1));
02657         $DB->set_field_select($tablename, 'onetext', false, 'id = ?', array(1));
02658         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
02659         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
02660         $this->assertEqual(0, $DB->get_field($tablename, 'onechar', array('id' => 1)));
02661         $this->assertEqual(0, $DB->get_field($tablename, 'onetext', array('id' => 1)));
02662 
02663         // Check string data causes exception in numeric types
02664         try {
02665             $DB->set_field_select($tablename, 'oneint', 'onestring', 'id = ?', array(1));
02666             $this->fail("Expecting an exception, none occurred");
02667         } catch (exception $e) {
02668             $this->assertTrue($e instanceof dml_exception);
02669         }
02670         try {
02671             $DB->set_field_select($tablename, 'onenum', 'onestring', 'id = ?', array(1));
02672             $this->fail("Expecting an exception, none occurred");
02673         } catch (exception $e) {
02674             $this->assertTrue($e instanceof dml_exception);
02675         }
02676 
02677         // Check empty string data is stored as 0 in numeric datatypes
02678         $DB->set_field_select($tablename, 'oneint', '', 'id = ?', array(1));
02679         $field = $DB->get_field($tablename, 'oneint', array('id' => 1));
02680         $this->assertTrue(is_numeric($field) && $field == 0);
02681 
02682         $DB->set_field_select($tablename, 'onenum', '', 'id = ?', array(1));
02683         $field = $DB->get_field($tablename, 'onenum', array('id' => 1));
02684         $this->assertTrue(is_numeric($field) && $field == 0);
02685 
02686         // Check empty strings are set properly in string types
02687         $DB->set_field_select($tablename, 'onechar', '', 'id = ?', array(1));
02688         $DB->set_field_select($tablename, 'onetext', '', 'id = ?', array(1));
02689         $this->assertTrue($DB->get_field($tablename, 'onechar', array('id' => 1)) === '');
02690         $this->assertTrue($DB->get_field($tablename, 'onetext', array('id' => 1)) === '');
02691 
02692         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
02693         $DB->set_field_select($tablename, 'oneint', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
02694         $DB->set_field_select($tablename, 'onenum', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
02695         $this->assertEqual(100, $DB->get_field($tablename, 'oneint', array('id' => 1)));
02696         $this->assertEqual(100, $DB->get_field($tablename, 'onenum', array('id' => 1)));
02697 
02698         // Check various quotes/backslashes combinations in string types
02699         $teststrings = array(
02700             'backslashes and quotes alone (even): "" \'\' \\\\',
02701             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
02702             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
02703             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
02704         foreach ($teststrings as $teststring) {
02705             $DB->set_field_select($tablename, 'onechar', $teststring, 'id = ?', array(1));
02706             $DB->set_field_select($tablename, 'onetext', $teststring, 'id = ?', array(1));
02707             $this->assertEqual($teststring, $DB->get_field($tablename, 'onechar', array('id' => 1)));
02708             $this->assertEqual($teststring, $DB->get_field($tablename, 'onetext', array('id' => 1)));
02709         }
02710 
02711         // Check LOBs in text/binary columns
02712         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
02713         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
02714         $DB->set_field_select($tablename, 'onetext', $clob, 'id = ?', array(1));
02715         $DB->set_field_select($tablename, 'onebinary', $blob, 'id = ?', array(1));
02716         $this->assertEqual($clob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test CLOB set_field (full contents output disabled)');
02717         $this->assertEqual($blob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test BLOB set_field (full contents output disabled)');
02718 
02719         // And "small" LOBs too, just in case
02720         $newclob = substr($clob, 0, 500);
02721         $newblob = substr($blob, 0, 250);
02722         $DB->set_field_select($tablename, 'onetext', $newclob, 'id = ?', array(1));
02723         $DB->set_field_select($tablename, 'onebinary', $newblob, 'id = ?', array(1));
02724         $this->assertEqual($newclob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test "small" CLOB set_field (full contents output disabled)');
02725         $this->assertEqual($newblob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test "small" BLOB set_field (full contents output disabled)');
02726 
02727         // This is the failure from MDL-24863. This was giving an error on MSSQL,
02728         // which converts the '1' to an integer, which cannot then be compared with
02729         // onetext cast to a varchar. This should be fixed and working now.
02730         $newchar = 'frog';
02731         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
02732         $params = array('onetext' => '1');
02733         try {
02734             $DB->set_field_select($tablename, 'onechar', $newchar, $DB->sql_compare_text('onetext') . ' = ?', $params);
02735             $this->assertTrue(true, 'No exceptions thrown with numerical text param comparison for text field.');
02736         } catch (dml_exception $e) {
02737             $this->assertFalse(true, 'We have an unexpected exception.');
02738             throw $e;
02739         }
02740 
02741 
02742     }
02743 
02744     public function test_count_records() {
02745         $DB = $this->tdb;
02746 
02747         $dbman = $DB->get_manager();
02748 
02749         $table = $this->get_test_table();
02750         $tablename = $table->getName();
02751 
02752         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02753         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02754         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
02755         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02756         $dbman->create_table($table);
02757 
02758         $this->assertEqual(0, $DB->count_records($tablename));
02759 
02760         $DB->insert_record($tablename, array('course' => 3));
02761         $DB->insert_record($tablename, array('course' => 4));
02762         $DB->insert_record($tablename, array('course' => 5));
02763 
02764         $this->assertEqual(3, $DB->count_records($tablename));
02765 
02766         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
02767         $conditions = array('onetext' => '1');
02768         try {
02769             $DB->count_records($tablename, $conditions);
02770             if (debugging()) {
02771                 // only in debug mode - hopefully all devs test code in debug mode...
02772                 $this->fail('An Exception is missing, expected due to equating of text fields');
02773             }
02774         } catch (exception $e) {
02775             $this->assertTrue($e instanceof dml_exception);
02776             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
02777         }
02778     }
02779 
02780     public function test_count_records_select() {
02781         $DB = $this->tdb;
02782 
02783         $dbman = $DB->get_manager();
02784 
02785         $table = $this->get_test_table();
02786         $tablename = $table->getName();
02787 
02788         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02789         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02790         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02791         $dbman->create_table($table);
02792 
02793         $this->assertEqual(0, $DB->count_records($tablename));
02794 
02795         $DB->insert_record($tablename, array('course' => 3));
02796         $DB->insert_record($tablename, array('course' => 4));
02797         $DB->insert_record($tablename, array('course' => 5));
02798 
02799         $this->assertEqual(2, $DB->count_records_select($tablename, 'course > ?', array(3)));
02800     }
02801 
02802     public function test_count_records_sql() {
02803         $DB = $this->tdb;
02804         $dbman = $DB->get_manager();
02805 
02806         $table = $this->get_test_table();
02807         $tablename = $table->getName();
02808 
02809         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02810         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02811         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02812         $dbman->create_table($table);
02813 
02814         $this->assertEqual(0, $DB->count_records($tablename));
02815 
02816         $DB->insert_record($tablename, array('course' => 3));
02817         $DB->insert_record($tablename, array('course' => 4));
02818         $DB->insert_record($tablename, array('course' => 5));
02819 
02820         $this->assertEqual(2, $DB->count_records_sql("SELECT COUNT(*) FROM {{$tablename}} WHERE course > ?", array(3)));
02821     }
02822 
02823     public function test_record_exists() {
02824         $DB = $this->tdb;
02825         $dbman = $DB->get_manager();
02826 
02827         $table = $this->get_test_table();
02828         $tablename = $table->getName();
02829 
02830         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02831         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02832         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
02833         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02834         $dbman->create_table($table);
02835 
02836         $this->assertEqual(0, $DB->count_records($tablename));
02837 
02838         $this->assertFalse($DB->record_exists($tablename, array('course' => 3)));
02839         $DB->insert_record($tablename, array('course' => 3));
02840 
02841         $this->assertTrue($DB->record_exists($tablename, array('course' => 3)));
02842 
02843 
02844         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
02845         $conditions = array('onetext' => '1');
02846         try {
02847             $DB->record_exists($tablename, $conditions);
02848             if (debugging()) {
02849                 // only in debug mode - hopefully all devs test code in debug mode...
02850                 $this->fail('An Exception is missing, expected due to equating of text fields');
02851             }
02852         } catch (exception $e) {
02853             $this->assertTrue($e instanceof dml_exception);
02854             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
02855         }
02856     }
02857 
02858     public function test_record_exists_select() {
02859         $DB = $this->tdb;
02860         $dbman = $DB->get_manager();
02861 
02862         $table = $this->get_test_table();
02863         $tablename = $table->getName();
02864 
02865         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02866         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02867         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02868         $dbman->create_table($table);
02869 
02870         $this->assertEqual(0, $DB->count_records($tablename));
02871 
02872         $this->assertFalse($DB->record_exists_select($tablename, "course = ?", array(3)));
02873         $DB->insert_record($tablename, array('course' => 3));
02874 
02875         $this->assertTrue($DB->record_exists_select($tablename, "course = ?", array(3)));
02876     }
02877 
02878     public function test_record_exists_sql() {
02879         $DB = $this->tdb;
02880         $dbman = $DB->get_manager();
02881 
02882         $table = $this->get_test_table();
02883         $tablename = $table->getName();
02884 
02885         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02886         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02887         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02888         $dbman->create_table($table);
02889 
02890         $this->assertEqual(0, $DB->count_records($tablename));
02891 
02892         $this->assertFalse($DB->record_exists_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3)));
02893         $DB->insert_record($tablename, array('course' => 3));
02894 
02895         $this->assertTrue($DB->record_exists_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3)));
02896     }
02897 
02898     public function test_recordset_locks_delete() {
02899         $DB = $this->tdb;
02900         $dbman = $DB->get_manager();
02901 
02902         //Setup
02903         $table = $this->get_test_table();
02904         $tablename = $table->getName();
02905 
02906         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02907         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02908         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02909         $dbman->create_table($table);
02910 
02911         $DB->insert_record($tablename, array('course' => 1));
02912         $DB->insert_record($tablename, array('course' => 2));
02913         $DB->insert_record($tablename, array('course' => 3));
02914         $DB->insert_record($tablename, array('course' => 4));
02915         $DB->insert_record($tablename, array('course' => 5));
02916         $DB->insert_record($tablename, array('course' => 6));
02917 
02918         // Test against db write locking while on an open recordset
02919         $rs = $DB->get_recordset($tablename, array(), null, 'course', 2, 2); // get courses = {3,4}
02920         foreach ($rs as $record) {
02921             $cid = $record->course;
02922             $DB->delete_records($tablename, array('course' => $cid));
02923             $this->assertFalse($DB->record_exists($tablename, array('course' => $cid)));
02924         }
02925         $rs->close();
02926 
02927         $this->assertEqual(4, $DB->count_records($tablename, array()));
02928     }
02929 
02930     public function test_recordset_locks_update() {
02931         $DB = $this->tdb;
02932         $dbman = $DB->get_manager();
02933 
02934         //Setup
02935         $table = $this->get_test_table();
02936         $tablename = $table->getName();
02937 
02938         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02939         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02940         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02941         $dbman->create_table($table);
02942 
02943         $DB->insert_record($tablename, array('course' => 1));
02944         $DB->insert_record($tablename, array('course' => 2));
02945         $DB->insert_record($tablename, array('course' => 3));
02946         $DB->insert_record($tablename, array('course' => 4));
02947         $DB->insert_record($tablename, array('course' => 5));
02948         $DB->insert_record($tablename, array('course' => 6));
02949 
02950         // Test against db write locking while on an open recordset
02951         $rs = $DB->get_recordset($tablename, array(), null, 'course', 2, 2); // get courses = {3,4}
02952         foreach ($rs as $record) {
02953             $cid = $record->course;
02954             $DB->set_field($tablename, 'course', 10, array('course' => $cid));
02955             $this->assertFalse($DB->record_exists($tablename, array('course' => $cid)));
02956         }
02957         $rs->close();
02958 
02959         $this->assertEqual(2, $DB->count_records($tablename, array('course' => 10)));
02960     }
02961 
02962     public function test_delete_records() {
02963         $DB = $this->tdb;
02964         $dbman = $DB->get_manager();
02965 
02966         $table = $this->get_test_table();
02967         $tablename = $table->getName();
02968 
02969         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
02970         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
02971         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
02972         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
02973         $dbman->create_table($table);
02974 
02975         $DB->insert_record($tablename, array('course' => 3));
02976         $DB->insert_record($tablename, array('course' => 2));
02977         $DB->insert_record($tablename, array('course' => 2));
02978 
02979         // Delete all records
02980         $this->assertTrue($DB->delete_records($tablename));
02981         $this->assertEqual(0, $DB->count_records($tablename));
02982 
02983         // Delete subset of records
02984         $DB->insert_record($tablename, array('course' => 3));
02985         $DB->insert_record($tablename, array('course' => 2));
02986         $DB->insert_record($tablename, array('course' => 2));
02987 
02988         $this->assertTrue($DB->delete_records($tablename, array('course' => 2)));
02989         $this->assertEqual(1, $DB->count_records($tablename));
02990 
02991         // delete all
02992         $this->assertTrue($DB->delete_records($tablename, array()));
02993         $this->assertEqual(0, $DB->count_records($tablename));
02994 
02995         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
02996         $conditions = array('onetext'=>'1');
02997         try {
02998             $DB->delete_records($tablename, $conditions);
02999             if (debugging()) {
03000                 // only in debug mode - hopefully all devs test code in debug mode...
03001                 $this->fail('An Exception is missing, expected due to equating of text fields');
03002             }
03003         } catch (exception $e) {
03004             $this->assertTrue($e instanceof dml_exception);
03005             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
03006         }
03007 
03008         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
03009         $conditions = array('onetext' => 1);
03010         try {
03011             $DB->delete_records($tablename, $conditions);
03012             if (debugging()) {
03013                 // only in debug mode - hopefully all devs test code in debug mode...
03014                 $this->fail('An Exception is missing, expected due to equating of text fields');
03015             }
03016         } catch (exception $e) {
03017             $this->assertTrue($e instanceof dml_exception);
03018             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
03019         }
03020     }
03021 
03022     public function test_delete_records_select() {
03023         $DB = $this->tdb;
03024         $dbman = $DB->get_manager();
03025 
03026         $table = $this->get_test_table();
03027         $tablename = $table->getName();
03028 
03029         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03030         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03031         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03032         $dbman->create_table($table);
03033 
03034         $DB->insert_record($tablename, array('course' => 3));
03035         $DB->insert_record($tablename, array('course' => 2));
03036         $DB->insert_record($tablename, array('course' => 2));
03037 
03038         $this->assertTrue($DB->delete_records_select($tablename, 'course = ?', array(2)));
03039         $this->assertEqual(1, $DB->count_records($tablename));
03040     }
03041 
03042     public function test_delete_records_list() {
03043         $DB = $this->tdb;
03044         $dbman = $DB->get_manager();
03045 
03046         $table = $this->get_test_table();
03047         $tablename = $table->getName();
03048 
03049         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03050         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03051         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03052         $dbman->create_table($table);
03053 
03054         $DB->insert_record($tablename, array('course' => 1));
03055         $DB->insert_record($tablename, array('course' => 2));
03056         $DB->insert_record($tablename, array('course' => 3));
03057 
03058         $this->assertTrue($DB->delete_records_list($tablename, 'course', array(2, 3)));
03059         $this->assertEqual(1, $DB->count_records($tablename));
03060 
03061         $this->assertTrue($DB->delete_records_list($tablename, 'course', array())); 
03062         $this->assertEqual(1, $DB->count_records($tablename));
03063     }
03064 
03065     function test_sql_null_from_clause() {
03066         $DB = $this->tdb;
03067         $sql = "SELECT 1 AS id ".$DB->sql_null_from_clause();
03068         $this->assertEqual($DB->get_field_sql($sql), 1);
03069     }
03070 
03071     function test_sql_bitand() {
03072         $DB = $this->tdb;
03073         $dbman = $DB->get_manager();
03074 
03075         $table = $this->get_test_table();
03076         $tablename = $table->getName();
03077 
03078         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03079         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03080         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03081         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03082         $dbman->create_table($table);
03083 
03084         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
03085 
03086         $sql = "SELECT ".$DB->sql_bitand(10, 3)." AS res ".$DB->sql_null_from_clause();
03087         $this->assertEqual($DB->get_field_sql($sql), 2);
03088 
03089         $sql = "SELECT id, ".$DB->sql_bitand('col1', 'col2')." AS res FROM {{$tablename}}";
03090         $result = $DB->get_records_sql($sql);
03091         $this->assertEqual(count($result), 1);
03092         $this->assertEqual(reset($result)->res, 2);
03093 
03094         $sql = "SELECT id, ".$DB->sql_bitand('col1', '?')." AS res FROM {{$tablename}}";
03095         $result = $DB->get_records_sql($sql, array(10));
03096         $this->assertEqual(count($result), 1);
03097         $this->assertEqual(reset($result)->res, 2);
03098     }
03099 
03100     function test_sql_bitnot() {
03101         $DB = $this->tdb;
03102 
03103         $not = $DB->sql_bitnot(2);
03104         $notlimited = $DB->sql_bitand($not, 7); // might be positive or negative number which can not fit into PHP INT!
03105 
03106         $sql = "SELECT $notlimited AS res ".$DB->sql_null_from_clause();
03107         $this->assertEqual($DB->get_field_sql($sql), 5);
03108     }
03109 
03110     function test_sql_bitor() {
03111         $DB = $this->tdb;
03112         $dbman = $DB->get_manager();
03113 
03114         $table = $this->get_test_table();
03115         $tablename = $table->getName();
03116 
03117         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03118         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03119         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03120         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03121         $dbman->create_table($table);
03122 
03123         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
03124 
03125         $sql = "SELECT ".$DB->sql_bitor(10, 3)." AS res ".$DB->sql_null_from_clause();
03126         $this->assertEqual($DB->get_field_sql($sql), 11);
03127 
03128         $sql = "SELECT id, ".$DB->sql_bitor('col1', 'col2')." AS res FROM {{$tablename}}";
03129         $result = $DB->get_records_sql($sql);
03130         $this->assertEqual(count($result), 1);
03131         $this->assertEqual(reset($result)->res, 11);
03132 
03133         $sql = "SELECT id, ".$DB->sql_bitor('col1', '?')." AS res FROM {{$tablename}}";
03134         $result = $DB->get_records_sql($sql, array(10));
03135         $this->assertEqual(count($result), 1);
03136         $this->assertEqual(reset($result)->res, 11);
03137     }
03138 
03139     function test_sql_bitxor() {
03140         $DB = $this->tdb;
03141         $dbman = $DB->get_manager();
03142 
03143         $table = $this->get_test_table();
03144         $tablename = $table->getName();
03145 
03146         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03147         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03148         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03149         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03150         $dbman->create_table($table);
03151 
03152         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
03153 
03154         $sql = "SELECT ".$DB->sql_bitxor(10, 3)." AS res ".$DB->sql_null_from_clause();
03155         $this->assertEqual($DB->get_field_sql($sql), 9);
03156 
03157         $sql = "SELECT id, ".$DB->sql_bitxor('col1', 'col2')." AS res FROM {{$tablename}}";
03158         $result = $DB->get_records_sql($sql);
03159         $this->assertEqual(count($result), 1);
03160         $this->assertEqual(reset($result)->res, 9);
03161 
03162         $sql = "SELECT id, ".$DB->sql_bitxor('col1', '?')." AS res FROM {{$tablename}}";
03163         $result = $DB->get_records_sql($sql, array(10));
03164         $this->assertEqual(count($result), 1);
03165         $this->assertEqual(reset($result)->res, 9);
03166     }
03167 
03168     function test_sql_modulo() {
03169         $DB = $this->tdb;
03170         $sql = "SELECT ".$DB->sql_modulo(10, 7)." AS res ".$DB->sql_null_from_clause();
03171         $this->assertEqual($DB->get_field_sql($sql), 3);
03172     }
03173 
03174     function test_sql_ceil() {
03175         $DB = $this->tdb;
03176         $sql = "SELECT ".$DB->sql_ceil(665.666)." AS res ".$DB->sql_null_from_clause();
03177         $this->assertEqual($DB->get_field_sql($sql), 666);
03178     }
03179 
03180     function test_cast_char2int() {
03181         $DB = $this->tdb;
03182         $dbman = $DB->get_manager();
03183 
03184         $table1 = $this->get_test_table("1");
03185         $tablename1 = $table1->getName();
03186 
03187         $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03188         $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03189         $table1->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
03190         $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03191         $dbman->create_table($table1);
03192 
03193         $DB->insert_record($tablename1, array('name'=>'0100', 'nametext'=>'0200'));
03194         $DB->insert_record($tablename1, array('name'=>'10',   'nametext'=>'20'));
03195 
03196         $table2 = $this->get_test_table("2");
03197         $tablename2 = $table2->getName();
03198         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03199         $table2->add_field('res', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03200         $table2->add_field('restext', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03201         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03202         $dbman->create_table($table2);
03203 
03204         $DB->insert_record($tablename2, array('res'=>100, 'restext'=>200));
03205 
03206         // casting varchar field
03207         $sql = "SELECT *
03208                   FROM {".$tablename1."} t1
03209                   JOIN {".$tablename2."} t2 ON ".$DB->sql_cast_char2int("t1.name")." = t2.res ";
03210         $records = $DB->get_records_sql($sql);
03211         $this->assertEqual(count($records), 1);
03212         // also test them in order clauses
03213         $sql = "SELECT * FROM {{$tablename1}} ORDER BY ".$DB->sql_cast_char2int('name');
03214         $records = $DB->get_records_sql($sql);
03215         $this->assertEqual(count($records), 2);
03216         $this->assertEqual(reset($records)->name, '10');
03217         $this->assertEqual(next($records)->name, '0100');
03218 
03219         // casting text field
03220         $sql = "SELECT *
03221                   FROM {".$tablename1."} t1
03222                   JOIN {".$tablename2."} t2 ON ".$DB->sql_cast_char2int("t1.nametext", true)." = t2.restext ";
03223         $records = $DB->get_records_sql($sql);
03224         $this->assertEqual(count($records), 1);
03225         // also test them in order clauses
03226         $sql = "SELECT * FROM {{$tablename1}} ORDER BY ".$DB->sql_cast_char2int('nametext', true);
03227         $records = $DB->get_records_sql($sql);
03228         $this->assertEqual(count($records), 2);
03229         $this->assertEqual(reset($records)->nametext, '20');
03230         $this->assertEqual(next($records)->nametext, '0200');
03231     }
03232 
03233     function test_cast_char2real() {
03234         $DB = $this->tdb;
03235         $dbman = $DB->get_manager();
03236 
03237         $table = $this->get_test_table();
03238         $tablename = $table->getName();
03239 
03240         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03241         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03242         $table->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
03243         $table->add_field('res', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null);
03244         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03245         $dbman->create_table($table);
03246 
03247         $DB->insert_record($tablename, array('name'=>'10.10', 'nametext'=>'10.10', 'res'=>5.1));
03248         $DB->insert_record($tablename, array('name'=>'91.10', 'nametext'=>'91.10', 'res'=>666));
03249         $DB->insert_record($tablename, array('name'=>'011.10','nametext'=>'011.10','res'=>10.1));
03250 
03251         // casting varchar field
03252         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_cast_char2real('name')." > res";
03253         $records = $DB->get_records_sql($sql);
03254         $this->assertEqual(count($records), 2);
03255         // also test them in order clauses
03256         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_cast_char2real('name');
03257         $records = $DB->get_records_sql($sql);
03258         $this->assertEqual(count($records), 3);
03259         $this->assertEqual(reset($records)->name, '10.10');
03260         $this->assertEqual(next($records)->name, '011.10');
03261         $this->assertEqual(next($records)->name, '91.10');
03262 
03263         // casting text field
03264         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_cast_char2real('nametext', true)." > res";
03265         $records = $DB->get_records_sql($sql);
03266         $this->assertEqual(count($records), 2);
03267         // also test them in order clauses
03268         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_cast_char2real('nametext', true);
03269         $records = $DB->get_records_sql($sql);
03270         $this->assertEqual(count($records), 3);
03271         $this->assertEqual(reset($records)->nametext, '10.10');
03272         $this->assertEqual(next($records)->nametext, '011.10');
03273         $this->assertEqual(next($records)->nametext, '91.10');
03274     }
03275 
03276     function sql_compare_text() {
03277         $DB = $this->tdb;
03278         $dbman = $DB->get_manager();
03279 
03280         $table = $this->get_test_table();
03281         $tablename = $table->getName();
03282 
03283         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03284         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03285         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
03286         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03287         $dbman->create_table($table);
03288 
03289         $DB->insert_record($tablename, array('name'=>'abcd',   'description'=>'abcd'));
03290         $DB->insert_record($tablename, array('name'=>'abcdef', 'description'=>'bbcdef'));
03291         $DB->insert_record($tablename, array('name'=>'aaaabb', 'description'=>'aaaacccccccccccccccccc'));
03292 
03293         $sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description');
03294         $records = $DB->get_records_sql($sql);
03295         $this->assertEqual(count($records), 1);
03296 
03297         $sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description', 4);
03298         $records = $DB->get_records_sql($sql);
03299         $this->assertEqual(count($records), 2);
03300     }
03301 
03302     function test_unique_index_collation_trouble() {
03303         // note: this is a work in progress, we should probably move this to ddl test
03304 
03305         $DB = $this->tdb;
03306         $dbman = $DB->get_manager();
03307 
03308         $table = $this->get_test_table();
03309         $tablename = $table->getName();
03310 
03311         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03312         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03313         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03314         $table->add_index('name', XMLDB_INDEX_UNIQUE, array('name'));
03315         $dbman->create_table($table);
03316 
03317         $DB->insert_record($tablename, array('name'=>'aaa'));
03318 
03319         try {
03320             $DB->insert_record($tablename, array('name'=>'AAA'));
03321         } catch (Exception $e) {
03322             //TODO: ignore case insensitive uniqueness problems for now
03323             //$this->fail("Unique index is case sensitive - this may cause problems in some tables");
03324         }
03325 
03326         try {
03327             $DB->insert_record($tablename, array('name'=>'aäa'));
03328             $DB->insert_record($tablename, array('name'=>'aáa'));
03329             $this->assertTrue(true);
03330         } catch (Exception $e) {
03331             $family = $DB->get_dbfamily();
03332             if ($family === 'mysql' or $family === 'mssql') {
03333                 $this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages. This is usually caused by accent insensitive default collation.");
03334             } else {
03335                 // this should not happen, PostgreSQL and Oracle do not support accent insensitive uniqueness.
03336                 $this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages.");
03337             }
03338             throw($e);
03339         }
03340     }
03341 
03342     function test_sql_binary_equal() {
03343         $DB = $this->tdb;
03344         $dbman = $DB->get_manager();
03345 
03346         $table = $this->get_test_table();
03347         $tablename = $table->getName();
03348 
03349         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03350         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03351         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03352         $dbman->create_table($table);
03353 
03354         $DB->insert_record($tablename, array('name'=>'aaa'));
03355         $DB->insert_record($tablename, array('name'=>'aáa'));
03356         $DB->insert_record($tablename, array('name'=>'aäa'));
03357         $DB->insert_record($tablename, array('name'=>'bbb'));
03358         $DB->insert_record($tablename, array('name'=>'BBB'));
03359 
03360         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('aaa'));
03361         $this->assertEqual(count($records), 1, 'SQL operator "=" is expected to be accent sensitive');
03362 
03363         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('bbb'));
03364         $this->assertEqual(count($records), 1, 'SQL operator "=" is expected to be case sensitive');
03365     }
03366 
03367     function test_sql_like() {
03368         $DB = $this->tdb;
03369         $dbman = $DB->get_manager();
03370 
03371         $table = $this->get_test_table();
03372         $tablename = $table->getName();
03373 
03374         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03375         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03376         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03377         $dbman->create_table($table);
03378 
03379         $DB->insert_record($tablename, array('name'=>'SuperDuperRecord'));
03380         $DB->insert_record($tablename, array('name'=>'Nodupor'));
03381         $DB->insert_record($tablename, array('name'=>'ouch'));
03382         $DB->insert_record($tablename, array('name'=>'ouc_'));
03383         $DB->insert_record($tablename, array('name'=>'ouc%'));
03384         $DB->insert_record($tablename, array('name'=>'aui'));
03385         $DB->insert_record($tablename, array('name'=>'aüi'));
03386         $DB->insert_record($tablename, array('name'=>'aÜi'));
03387 
03388         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false);
03389         $records = $DB->get_records_sql($sql, array("%dup_r%"));
03390         $this->assertEqual(count($records), 2);
03391 
03392         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true);
03393         $records = $DB->get_records_sql($sql, array("%dup%"));
03394         $this->assertEqual(count($records), 1);
03395 
03396         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?'); // defaults
03397         $records = $DB->get_records_sql($sql, array("%dup%"));
03398         $this->assertEqual(count($records), 1);
03399 
03400         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true);
03401         $records = $DB->get_records_sql($sql, array("ouc\\_"));
03402         $this->assertEqual(count($records), 1);
03403 
03404         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true, false, '|');
03405         $records = $DB->get_records_sql($sql, array($DB->sql_like_escape("ouc%", '|')));
03406         $this->assertEqual(count($records), 1);
03407 
03408         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true);
03409         $records = $DB->get_records_sql($sql, array('aui'));
03410         $this->assertEqual(count($records), 1);
03411 
03412         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true, true); // NOT LIKE
03413         $records = $DB->get_records_sql($sql, array("%o%"));
03414         $this->assertEqual(count($records), 3);
03415 
03416         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false, true, true); // NOT ILIKE
03417         $records = $DB->get_records_sql($sql, array("%D%"));
03418         $this->assertEqual(count($records), 6);
03419 
03420         // TODO: we do not require accent insensitivness yet, just make sure it does not throw errors
03421         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, false);
03422         $records = $DB->get_records_sql($sql, array('aui'));
03423         //$this->assertEqual(count($records), 2, 'Accent insensitive LIKE searches may not be supported in all databases, this is not a problem.');
03424         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false, false);
03425         $records = $DB->get_records_sql($sql, array('aui'));
03426         //$this->assertEqual(count($records), 3, 'Accent insensitive LIKE searches may not be supported in all databases, this is not a problem.');
03427     }
03428 
03429     function test_sql_ilike() {
03430         // note: this is deprecated, just make sure it does not throw error
03431         $DB = $this->tdb;
03432         $dbman = $DB->get_manager();
03433 
03434         $table = $this->get_test_table();
03435         $tablename = $table->getName();
03436 
03437         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03438         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03439         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03440         $dbman->create_table($table);
03441 
03442         $DB->insert_record($tablename, array('name'=>'SuperDuperRecord'));
03443         $DB->insert_record($tablename, array('name'=>'NoDupor'));
03444         $DB->insert_record($tablename, array('name'=>'ouch'));
03445 
03446         // make sure it prints debug message
03447         $this->enable_debugging();
03448         $sql = "SELECT * FROM {{$tablename}} WHERE name ".$DB->sql_ilike()." ?";
03449         $params = array("%dup_r%");
03450         $this->assertFalse($this->get_debugging() === '');
03451 
03452         // following must not throw exception, we ignore result
03453         $DB->get_records_sql($sql, $params);
03454     }
03455 
03456     function test_coalesce() {
03457         $DB = $this->tdb;
03458 
03459         // Testing not-null ocurrences, return 1st
03460         $sql = "SELECT COALESCE('returnthis', 'orthis', 'orwhynotthis') AS test" . $DB->sql_null_from_clause();
03461         $this->assertEqual('returnthis', $DB->get_field_sql($sql, array()));
03462         $sql = "SELECT COALESCE(:paramvalue, 'orthis', 'orwhynotthis') AS test" . $DB->sql_null_from_clause();
03463         $this->assertEqual('returnthis', $DB->get_field_sql($sql, array('paramvalue' => 'returnthis')));
03464 
03465         // Testing null ocurrences, return 2nd
03466         $sql = "SELECT COALESCE(null, 'returnthis', 'orthis') AS test" . $DB->sql_null_from_clause();
03467         $this->assertEqual('returnthis', $DB->get_field_sql($sql, array()));
03468         $sql = "SELECT COALESCE(:paramvalue, 'returnthis', 'orthis') AS test" . $DB->sql_null_from_clause();
03469         $this->assertEqual('returnthis', $DB->get_field_sql($sql, array('paramvalue' => null)));
03470         $sql = "SELECT COALESCE(null, :paramvalue, 'orthis') AS test" . $DB->sql_null_from_clause();
03471         $this->assertEqual('returnthis', $DB->get_field_sql($sql, array('paramvalue' => 'returnthis')));
03472 
03473         // Testing null ocurrences, return 3rd
03474         $sql = "SELECT COALESCE(null, null, 'returnthis') AS test" . $DB->sql_null_from_clause();
03475         $this->assertEqual('returnthis', $DB->get_field_sql($sql, array()));
03476         $sql = "SELECT COALESCE(null, :paramvalue, 'returnthis') AS test" . $DB->sql_null_from_clause();
03477         $this->assertEqual('returnthis', $DB->get_field_sql($sql, array('paramvalue' => null)));
03478         $sql = "SELECT COALESCE(null, null, :paramvalue) AS test" . $DB->sql_null_from_clause();
03479         $this->assertEqual('returnthis', $DB->get_field_sql($sql, array('paramvalue' => 'returnthis')));
03480 
03481         // Testing all null ocurrences, return null
03482         // Note: under mssql, if all elements are nulls, at least one must be a "typed" null, hence
03483         // we cannot test this in a cross-db way easily, so next 2 tests are using
03484         // different queries depending of the DB family
03485         $customnull = $DB->get_dbfamily() == 'mssql' ? 'CAST(null AS varchar)' : 'null';
03486         $sql = "SELECT COALESCE(null, null, " . $customnull . ") AS test" . $DB->sql_null_from_clause();
03487         $this->assertNull($DB->get_field_sql($sql, array()));
03488         $sql = "SELECT COALESCE(null, :paramvalue, " . $customnull . ") AS test" . $DB->sql_null_from_clause();
03489         $this->assertNull($DB->get_field_sql($sql, array('paramvalue' => null)));
03490 
03491         // Check there are not problems with whitespace strings
03492         $sql = "SELECT COALESCE(null, '', null) AS test" . $DB->sql_null_from_clause();
03493         $this->assertEqual('', $DB->get_field_sql($sql, array()));
03494         $sql = "SELECT COALESCE(null, :paramvalue, null) AS test" . $DB->sql_null_from_clause();
03495         $this->assertEqual('', $DB->get_field_sql($sql, array('paramvalue' => '')));
03496     }
03497 
03498     function test_sql_concat() {
03499         $DB = $this->tdb;
03500         $dbman = $DB->get_manager();
03501 
03503         $sql = "SELECT ".$DB->sql_concat("?", "?", "?")." AS fullname ". $DB->sql_null_from_clause();
03504         // string, some unicode chars
03505         $params = array('name', 'áéíóú', 'name3');
03506         $this->assertEqual('nameáéíóúname3', $DB->get_field_sql($sql, $params));
03507         // string, spaces and numbers
03508         $params = array('name', '  ', 12345);
03509         $this->assertEqual('name  12345', $DB->get_field_sql($sql, $params));
03510         // float, empty and strings
03511         $params = array(123.45, '', 'test');
03512         $this->assertEqual('123.45test', $DB->get_field_sql($sql, $params));
03513         // only integers
03514         $params = array(12, 34, 56);
03515         $this->assertEqual('123456', $DB->get_field_sql($sql, $params));
03516         // float, null and strings
03517         $params = array(123.45, null, 'test');
03518         $this->assertNull($DB->get_field_sql($sql, $params), 'ANSI behaviour: Concatenating NULL must return NULL - But in Oracle :-(. [%s]'); // Concatenate NULL with anything result = NULL
03519 
03521         $table = $this->get_test_table();
03522         $tablename = $table->getName();
03523 
03524         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03525         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
03526         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03527         $dbman->create_table($table);
03528 
03529         $DB->insert_record($tablename, array('description'=>'áéíóú'));
03530         $DB->insert_record($tablename, array('description'=>'dxxx'));
03531         $DB->insert_record($tablename, array('description'=>'bcde'));
03532 
03533         // fieldnames and values mixed
03534         $sql = 'SELECT id, ' . $DB->sql_concat('description', "'harcoded'", '?', '?') . ' AS result FROM {' . $tablename . '}';
03535         $records = $DB->get_records_sql($sql, array(123.45, 'test'));
03536         $this->assertEqual(count($records), 3);
03537         $this->assertEqual($records[1]->result, 'áéíóúharcoded123.45test');
03538         // integer fieldnames and values
03539         $sql = 'SELECT id, ' . $DB->sql_concat('id', "'harcoded'", '?', '?') . ' AS result FROM {' . $tablename . '}';
03540         $records = $DB->get_records_sql($sql, array(123.45, 'test'));
03541         $this->assertEqual(count($records), 3);
03542         $this->assertEqual($records[1]->result, '1harcoded123.45test');
03543         // all integer fieldnames
03544         $sql = 'SELECT id, ' . $DB->sql_concat('id', 'id', 'id') . ' AS result FROM {' . $tablename . '}';
03545         $records = $DB->get_records_sql($sql, array());
03546         $this->assertEqual(count($records), 3);
03547         $this->assertEqual($records[1]->result, '111');
03548 
03549     }
03550 
03551     function test_concat_join() {
03552         $DB = $this->tdb;
03553         $sql = "SELECT ".$DB->sql_concat_join("' '", array("?", "?", "?"))." AS fullname ".$DB->sql_null_from_clause();
03554         $params = array("name", "name2", "name3");
03555         $result = $DB->get_field_sql($sql, $params);
03556         $this->assertEqual("name name2 name3", $result);
03557     }
03558 
03559     function test_sql_fullname() {
03560         $DB = $this->tdb;
03561         $sql = "SELECT ".$DB->sql_fullname(':first', ':last')." AS fullname ".$DB->sql_null_from_clause();
03562         $params = array('first'=>'Firstname', 'last'=>'Surname');
03563         $this->assertEqual("Firstname Surname", $DB->get_field_sql($sql, $params));
03564     }
03565 
03566     function sql_sql_order_by_text() {
03567         $DB = $this->tdb;
03568         $dbman = $DB->get_manager();
03569 
03570         $table = $this->get_test_table();
03571         $tablename = $table->getName();
03572 
03573         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03574         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
03575         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03576         $dbman->create_table($table);
03577 
03578         $DB->insert_record($tablename, array('description'=>'abcd'));
03579         $DB->insert_record($tablename, array('description'=>'dxxx'));
03580         $DB->insert_record($tablename, array('description'=>'bcde'));
03581 
03582         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_order_by_text('description');
03583         $records = $DB->get_records_sql($sql);
03584         $first = array_shift($records);
03585         $this->assertEqual(1, $first->id);
03586         $second = array_shift($records);
03587         $this->assertEqual(3, $second->id);
03588         $last = array_shift($records);
03589         $this->assertEqual(2, $last->id);
03590     }
03591 
03592     function test_sql_substring() {
03593         $DB = $this->tdb;
03594         $dbman = $DB->get_manager();
03595 
03596         $table = $this->get_test_table();
03597         $tablename = $table->getName();
03598 
03599         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03600         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03601         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03602         $dbman->create_table($table);
03603 
03604         $string = 'abcdefghij';
03605 
03606         $DB->insert_record($tablename, array('name'=>$string));
03607 
03608         $sql = "SELECT id, ".$DB->sql_substr("name", 5)." AS name FROM {{$tablename}}";
03609         $record = $DB->get_record_sql($sql);
03610         $this->assertEqual(substr($string, 5-1), $record->name);
03611 
03612         $sql = "SELECT id, ".$DB->sql_substr("name", 5, 2)." AS name FROM {{$tablename}}";
03613         $record = $DB->get_record_sql($sql);
03614         $this->assertEqual(substr($string, 5-1, 2), $record->name);
03615 
03616         try {
03617             // silence php warning ;-)
03618             @$DB->sql_substr("name");
03619             $this->fail("Expecting an exception, none occurred");
03620         } catch (Exception $e) {
03621             $this->assertTrue($e instanceof coding_exception);
03622         }
03623     }
03624 
03625     function test_sql_length() {
03626         $DB = $this->tdb;
03627         $this->assertEqual($DB->get_field_sql(
03628                 "SELECT ".$DB->sql_length("'aeiou'").$DB->sql_null_from_clause()), 5);
03629         $this->assertEqual($DB->get_field_sql(
03630                 "SELECT ".$DB->sql_length("'áéíóú'").$DB->sql_null_from_clause()), 5);
03631     }
03632 
03633     function test_sql_position() {
03634         $DB = $this->tdb;
03635         $this->assertEqual($DB->get_field_sql(
03636                 "SELECT ".$DB->sql_position("'ood'", "'Moodle'").$DB->sql_null_from_clause()), 2);
03637         $this->assertEqual($DB->get_field_sql(
03638                 "SELECT ".$DB->sql_position("'Oracle'", "'Moodle'").$DB->sql_null_from_clause()), 0);
03639     }
03640 
03641     function test_sql_empty() {
03642         $DB = $this->tdb;
03643         $dbman = $DB->get_manager();
03644 
03645         $table = $this->get_test_table();
03646         $tablename = $table->getName();
03647 
03648         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03649         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03650         $table->add_field('namenotnull', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'default value');
03651         $table->add_field('namenotnullnodeflt', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
03652         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03653         $dbman->create_table($table);
03654 
03655         $DB->insert_record($tablename, array('name'=>'', 'namenotnull'=>''));
03656         $DB->insert_record($tablename, array('name'=>null));
03657         $DB->insert_record($tablename, array('name'=>'lalala'));
03658         $DB->insert_record($tablename, array('name'=>0));
03659 
03660         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = '".$DB->sql_empty()."'");
03661         $this->assertEqual(count($records), 1);
03662         $record = reset($records);
03663         $this->assertEqual($record->name, '');
03664 
03665         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE namenotnull = '".$DB->sql_empty()."'");
03666         $this->assertEqual(count($records), 1);
03667         $record = reset($records);
03668         $this->assertEqual($record->namenotnull, '');
03669 
03670         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE namenotnullnodeflt = '".$DB->sql_empty()."'");
03671         $this->assertEqual(count($records), 4);
03672         $record = reset($records);
03673         $this->assertEqual($record->namenotnullnodeflt, '');
03674     }
03675 
03676     function test_sql_isempty() {
03677         $DB = $this->tdb;
03678         $dbman = $DB->get_manager();
03679 
03680         $table = $this->get_test_table();
03681         $tablename = $table->getName();
03682 
03683         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03684         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
03685         $table->add_field('namenull', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03686         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null);
03687         $table->add_field('descriptionnull', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
03688         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03689         $dbman->create_table($table);
03690 
03691         $DB->insert_record($tablename, array('name'=>'',   'namenull'=>'',   'description'=>'',   'descriptionnull'=>''));
03692         $DB->insert_record($tablename, array('name'=>'??', 'namenull'=>null, 'description'=>'??', 'descriptionnull'=>null));
03693         $DB->insert_record($tablename, array('name'=>'la', 'namenull'=>'la', 'description'=>'la', 'descriptionnull'=>'lalala'));
03694         $DB->insert_record($tablename, array('name'=>0,    'namenull'=>0,    'description'=>0,    'descriptionnull'=>0));
03695 
03696         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isempty($tablename, 'name', false, false));
03697         $this->assertEqual(count($records), 1);
03698         $record = reset($records);
03699         $this->assertEqual($record->name, '');
03700 
03701         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isempty($tablename, 'namenull', true, false));
03702         $this->assertEqual(count($records), 1);
03703         $record = reset($records);
03704         $this->assertEqual($record->namenull, '');
03705 
03706         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isempty($tablename, 'description', false, true));
03707         $this->assertEqual(count($records), 1);
03708         $record = reset($records);
03709         $this->assertEqual($record->description, '');
03710 
03711         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isempty($tablename, 'descriptionnull', true, true));
03712         $this->assertEqual(count($records), 1);
03713         $record = reset($records);
03714         $this->assertEqual($record->descriptionnull, '');
03715     }
03716 
03717     function test_sql_isnotempty() {
03718         $DB = $this->tdb;
03719         $dbman = $DB->get_manager();
03720 
03721         $table = $this->get_test_table();
03722         $tablename = $table->getName();
03723 
03724         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03725         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
03726         $table->add_field('namenull', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03727         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null);
03728         $table->add_field('descriptionnull', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
03729         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03730         $dbman->create_table($table);
03731 
03732         $DB->insert_record($tablename, array('name'=>'',   'namenull'=>'',   'description'=>'',   'descriptionnull'=>''));
03733         $DB->insert_record($tablename, array('name'=>'??', 'namenull'=>null, 'description'=>'??', 'descriptionnull'=>null));
03734         $DB->insert_record($tablename, array('name'=>'la', 'namenull'=>'la', 'description'=>'la', 'descriptionnull'=>'lalala'));
03735         $DB->insert_record($tablename, array('name'=>0,    'namenull'=>0,    'description'=>0,    'descriptionnull'=>0));
03736 
03737         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isnotempty($tablename, 'name', false, false));
03738         $this->assertEqual(count($records), 3);
03739         $record = reset($records);
03740         $this->assertEqual($record->name, '??');
03741 
03742         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isnotempty($tablename, 'namenull', true, false));
03743         $this->assertEqual(count($records), 2); // nulls aren't comparable (so they aren't "not empty"). SQL expected behaviour
03744         $record = reset($records);
03745         $this->assertEqual($record->namenull, 'la'); // so 'la' is the first non-empty 'namenull' record
03746 
03747         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isnotempty($tablename, 'description', false, true));
03748         $this->assertEqual(count($records), 3);
03749         $record = reset($records);
03750         $this->assertEqual($record->description, '??');
03751 
03752         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isnotempty($tablename, 'descriptionnull', true, true));
03753         $this->assertEqual(count($records), 2); // nulls aren't comparable (so they aren't "not empty"). SQL expected behaviour
03754         $record = reset($records);
03755         $this->assertEqual($record->descriptionnull, 'lalala'); // so 'lalala' is the first non-empty 'descriptionnull' record
03756     }
03757 
03758     function test_sql_regex() {
03759         $DB = $this->tdb;
03760         $dbman = $DB->get_manager();
03761 
03762         $table = $this->get_test_table();
03763         $tablename = $table->getName();
03764 
03765         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03766         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03767         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03768         $dbman->create_table($table);
03769 
03770         $DB->insert_record($tablename, array('name'=>'lalala'));
03771         $DB->insert_record($tablename, array('name'=>'holaaa'));
03772         $DB->insert_record($tablename, array('name'=>'aouch'));
03773 
03774         $sql = "SELECT * FROM {{$tablename}} WHERE name ".$DB->sql_regex()." ?";
03775         $params = array('a$');
03776         if ($DB->sql_regex_supported()) {
03777             $records = $DB->get_records_sql($sql, $params);
03778             $this->assertEqual(count($records), 2);
03779         } else {
03780             $this->assertTrue(true, 'Regexp operations not supported. Test skipped');
03781         }
03782 
03783         $sql = "SELECT * FROM {{$tablename}} WHERE name ".$DB->sql_regex(false)." ?";
03784         $params = array('.a');
03785         if ($DB->sql_regex_supported()) {
03786             $records = $DB->get_records_sql($sql, $params);
03787             $this->assertEqual(count($records), 1);
03788         } else {
03789             $this->assertTrue(true, 'Regexp operations not supported. Test skipped');
03790         }
03791 
03792     }
03793 
03798     public function test_get_records_sql_complicated() {
03799         $DB = $this->tdb;
03800         $dbman = $DB->get_manager();
03801 
03802         $table = $this->get_test_table();
03803         $tablename = $table->getName();
03804 
03805         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03806         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03807         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
03808         $table->add_field('content', XMLDB_TYPE_TEXT, 'big', XMLDB_UNSIGNED, XMLDB_NOTNULL);
03809         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03810         $dbman->create_table($table);
03811 
03812         $DB->insert_record($tablename, array('course' => 3, 'content' => 'hello', 'name'=>'xyz'));
03813         $DB->insert_record($tablename, array('course' => 3, 'content' => 'world', 'name'=>'abc'));
03814         $DB->insert_record($tablename, array('course' => 5, 'content' => 'hello', 'name'=>'def'));
03815         $DB->insert_record($tablename, array('course' => 2, 'content' => 'universe', 'name'=>'abc'));
03816 
03817         // test grouping by expressions in the query. MDL-26819. Note that there are 4 ways:
03818         // - By column position (GROUP by 1) - Not supported by mssql & oracle
03819         // - By column name (GROUP by course) - Supported by all, but leading to wrong results
03820         // - By column alias (GROUP by casecol) - Not supported by mssql & oracle
03821         // - By complete expression (GROUP BY CASE ...) - 100% cross-db, this test checks it
03822         $sql = "SELECT (CASE WHEN course = 3 THEN 1 ELSE 0 END) AS casecol,
03823                        COUNT(1) AS countrecs,
03824                        MAX(name) AS maxname
03825                   FROM {{$tablename}}
03826               GROUP BY CASE WHEN course = 3 THEN 1 ELSE 0 END
03827               ORDER BY casecol DESC";
03828         $result = array(
03829                 1 => (object)array('casecol' => 1, 'countrecs' => 2, 'maxname' => 'xyz'),
03830                 0 => (object)array('casecol' => 0, 'countrecs' => 2, 'maxname' => 'def'));
03831         $records = $DB->get_records_sql($sql, null);
03832         $this->assertEqual($result, $records);
03833 
03834         // another grouping by CASE expression just to ensure it works ok for multiple WHEN
03835         $sql = "SELECT CASE name
03836                             WHEN 'xyz' THEN 'last'
03837                             WHEN 'def' THEN 'mid'
03838                             WHEN 'abc' THEN 'first'
03839                        END AS casecol,
03840                        COUNT(1) AS countrecs,
03841                        MAX(name) AS maxname
03842                   FROM {{$tablename}}
03843               GROUP BY CASE name
03844                            WHEN 'xyz' THEN 'last'
03845                            WHEN 'def' THEN 'mid'
03846                            WHEN 'abc' THEN 'first'
03847                        END
03848               ORDER BY casecol DESC";
03849         $result = array(
03850                 'mid'  => (object)array('casecol' => 'mid', 'countrecs' => 1, 'maxname' => 'def'),
03851                 'last' => (object)array('casecol' => 'last', 'countrecs' => 1, 'maxname' => 'xyz'),
03852                 'first'=> (object)array('casecol' => 'first', 'countrecs' => 2, 'maxname' => 'abc'));
03853         $records = $DB->get_records_sql($sql, null);
03854         $this->assertEqual($result, $records);
03855 
03856         // test limits in queries with DISTINCT/ALL clauses and multiple whitespace. MDL-25268
03857         $sql = "SELECT   DISTINCT   course
03858                   FROM {{$tablename}}
03859                  ORDER BY course";
03860         // only limitfrom
03861         $records = $DB->get_records_sql($sql, null, 1);
03862         $this->assertEqual(2, count($records));
03863         $this->assertEqual(3, reset($records)->course);
03864         $this->assertEqual(5, next($records)->course);
03865         // only limitnum
03866         $records = $DB->get_records_sql($sql, null, 0, 2);
03867         $this->assertEqual(2, count($records));
03868         $this->assertEqual(2, reset($records)->course);
03869         $this->assertEqual(3, next($records)->course);
03870         // both limitfrom and limitnum
03871         $records = $DB->get_records_sql($sql, null, 2, 2);
03872         $this->assertEqual(1, count($records));
03873         $this->assertEqual(5, reset($records)->course);
03874 
03875         // we have sql like this in moodle, this syntax breaks on older versions of sqlite for example..
03876         $sql = "SELECT a.id AS id, a.course AS course
03877                   FROM {{$tablename}} a
03878                   JOIN (SELECT * FROM {{$tablename}}) b ON a.id = b.id
03879                  WHERE a.course = ?";
03880 
03881         $records = $DB->get_records_sql($sql, array(3));
03882         $this->assertEqual(2, count($records));
03883         $this->assertEqual(1, reset($records)->id);
03884         $this->assertEqual(2, next($records)->id);
03885 
03886         // do NOT try embedding sql_xxxx() helper functions in conditions array of count_records(), they don't break params/binding!
03887         $count = $DB->count_records_select($tablename, "course = :course AND ".$DB->sql_compare_text('content')." = :content", array('course' => 3, 'content' => 'hello'));
03888         $this->assertEqual(1, $count);
03889 
03890         // test int x string comparison
03891         $sql = "SELECT *
03892                   FROM {{$tablename}} c
03893                  WHERE name = ?";
03894         $this->assertEqual(count($DB->get_records_sql($sql, array(10))), 0);
03895         $this->assertEqual(count($DB->get_records_sql($sql, array("10"))), 0);
03896         $DB->insert_record($tablename, array('course' => 7, 'content' => 'xx', 'name'=>'1'));
03897         $DB->insert_record($tablename, array('course' => 7, 'content' => 'yy', 'name'=>'2'));
03898         $this->assertEqual(count($DB->get_records_sql($sql, array(1))), 1);
03899         $this->assertEqual(count($DB->get_records_sql($sql, array("1"))), 1);
03900         $this->assertEqual(count($DB->get_records_sql($sql, array(10))), 0);
03901         $this->assertEqual(count($DB->get_records_sql($sql, array("10"))), 0);
03902         $DB->insert_record($tablename, array('course' => 7, 'content' => 'xx', 'name'=>'1abc'));
03903         $this->assertEqual(count($DB->get_records_sql($sql, array(1))), 1);
03904         $this->assertEqual(count($DB->get_records_sql($sql, array("1"))), 1);
03905     }
03906 
03907     function test_onelevel_commit() {
03908         $DB = $this->tdb;
03909         $dbman = $DB->get_manager();
03910 
03911         $table = $this->get_test_table();
03912         $tablename = $table->getName();
03913 
03914         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03915         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03916         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03917         $dbman->create_table($table);
03918 
03919         $transaction = $DB->start_delegated_transaction();
03920         $data = (object)array('course'=>3);
03921         $this->assertEqual(0, $DB->count_records($tablename));
03922         $DB->insert_record($tablename, $data);
03923         $this->assertEqual(1, $DB->count_records($tablename));
03924         $transaction->allow_commit();
03925         $this->assertEqual(1, $DB->count_records($tablename));
03926     }
03927 
03928     function test_onelevel_rollback() {
03929         $DB = $this->tdb;
03930         $dbman = $DB->get_manager();
03931 
03932         $table = $this->get_test_table();
03933         $tablename = $table->getName();
03934 
03935         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03936         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03937         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03938         $dbman->create_table($table);
03939 
03940         // this might in fact encourage ppl to migrate from myisam to innodb
03941 
03942         $transaction = $DB->start_delegated_transaction();
03943         $data = (object)array('course'=>3);
03944         $this->assertEqual(0, $DB->count_records($tablename));
03945         $DB->insert_record($tablename, $data);
03946         $this->assertEqual(1, $DB->count_records($tablename));
03947         try {
03948             $transaction->rollback(new Exception('test'));
03949             $this->fail('transaction rollback must rethrow exception');
03950         } catch (Exception $e) {
03951         }
03952         $this->assertEqual(0, $DB->count_records($tablename));
03953     }
03954 
03955     function test_nested_transactions() {
03956         $DB = $this->tdb;
03957         $dbman = $DB->get_manager();
03958 
03959         $table = $this->get_test_table();
03960         $tablename = $table->getName();
03961 
03962         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
03963         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
03964         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
03965         $dbman->create_table($table);
03966 
03967         // two level commit
03968         $this->assertFalse($DB->is_transaction_started());
03969         $transaction1 = $DB->start_delegated_transaction();
03970         $this->assertTrue($DB->is_transaction_started());
03971         $data = (object)array('course'=>3);
03972         $DB->insert_record($tablename, $data);
03973         $transaction2 = $DB->start_delegated_transaction();
03974         $data = (object)array('course'=>4);
03975         $DB->insert_record($tablename, $data);
03976         $transaction2->allow_commit();
03977         $this->assertTrue($DB->is_transaction_started());
03978         $transaction1->allow_commit();
03979         $this->assertFalse($DB->is_transaction_started());
03980         $this->assertEqual(2, $DB->count_records($tablename));
03981 
03982         $DB->delete_records($tablename);
03983 
03984         // rollback from top level
03985         $transaction1 = $DB->start_delegated_transaction();
03986         $data = (object)array('course'=>3);
03987         $DB->insert_record($tablename, $data);
03988         $transaction2 = $DB->start_delegated_transaction();
03989         $data = (object)array('course'=>4);
03990         $DB->insert_record($tablename, $data);
03991         $transaction2->allow_commit();
03992         try {
03993             $transaction1->rollback(new Exception('test'));
03994             $this->fail('transaction rollback must rethrow exception');
03995         } catch (Exception $e) {
03996             $this->assertEqual(get_class($e), 'Exception');
03997         }
03998         $this->assertEqual(0, $DB->count_records($tablename));
03999 
04000         $DB->delete_records($tablename);
04001 
04002         // rollback from nested level
04003         $transaction1 = $DB->start_delegated_transaction();
04004         $data = (object)array('course'=>3);
04005         $DB->insert_record($tablename, $data);
04006         $transaction2 = $DB->start_delegated_transaction();
04007         $data = (object)array('course'=>4);
04008         $DB->insert_record($tablename, $data);
04009         try {
04010             $transaction2->rollback(new Exception('test'));
04011             $this->fail('transaction rollback must rethrow exception');
04012         } catch (Exception $e) {
04013             $this->assertEqual(get_class($e), 'Exception');
04014         }
04015         $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet
04016         try {
04017             $transaction1->allow_commit();
04018         } catch (Exception $e) {
04019             $this->assertEqual(get_class($e), 'dml_transaction_exception');
04020         }
04021         $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet
04022         // the forced rollback is done from the default_exception handler and similar places,
04023         // let's do it manually here
04024         $this->assertTrue($DB->is_transaction_started());
04025         $DB->force_transaction_rollback();
04026         $this->assertFalse($DB->is_transaction_started());
04027         $this->assertEqual(0, $DB->count_records($tablename)); // finally rolled back
04028 
04029         $DB->delete_records($tablename);
04030     }
04031 
04032     function test_transactions_forbidden() {
04033         $DB = $this->tdb;
04034         $dbman = $DB->get_manager();
04035 
04036         $table = $this->get_test_table();
04037         $tablename = $table->getName();
04038 
04039         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
04040         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
04041         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
04042         $dbman->create_table($table);
04043 
04044         $DB->transactions_forbidden();
04045         $transaction = $DB->start_delegated_transaction();
04046         $data = (object)array('course'=>1);
04047         $DB->insert_record($tablename, $data);
04048         try {
04049             $DB->transactions_forbidden();
04050         } catch (Exception $e) {
04051             $this->assertEqual(get_class($e), 'dml_transaction_exception');
04052         }
04053         // the previous test does not force rollback
04054         $transaction->allow_commit();
04055         $this->assertFalse($DB->is_transaction_started());
04056         $this->assertEqual(1, $DB->count_records($tablename));
04057     }
04058 
04059     function test_wrong_transactions() {
04060         $DB = $this->tdb;
04061         $dbman = $DB->get_manager();
04062 
04063         $table = $this->get_test_table();
04064         $tablename = $table->getName();
04065 
04066         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
04067         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
04068         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
04069         $dbman->create_table($table);
04070 
04071 
04072         // wrong order of nested commits
04073         $transaction1 = $DB->start_delegated_transaction();
04074         $data = (object)array('course'=>3);
04075         $DB->insert_record($tablename, $data);
04076         $transaction2 = $DB->start_delegated_transaction();
04077         $data = (object)array('course'=>4);
04078         $DB->insert_record($tablename, $data);
04079         try {
04080             $transaction1->allow_commit();
04081             $this->fail('wrong order of commits must throw exception');
04082         } catch (Exception $e) {
04083             $this->assertEqual(get_class($e), 'dml_transaction_exception');
04084         }
04085         try {
04086             $transaction2->allow_commit();
04087             $this->fail('first wrong commit forces rollback');
04088         } catch (Exception $e) {
04089             $this->assertEqual(get_class($e), 'dml_transaction_exception');
04090         }
04091         // this is done in default exception handler usually
04092         $this->assertTrue($DB->is_transaction_started());
04093         $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet
04094         $DB->force_transaction_rollback();
04095         $this->assertEqual(0, $DB->count_records($tablename));
04096         $DB->delete_records($tablename);
04097 
04098 
04099         // wrong order of nested rollbacks
04100         $transaction1 = $DB->start_delegated_transaction();
04101         $data = (object)array('course'=>3);
04102         $DB->insert_record($tablename, $data);
04103         $transaction2 = $DB->start_delegated_transaction();
04104         $data = (object)array('course'=>4);
04105         $DB->insert_record($tablename, $data);
04106         try {
04107             // this first rollback should prevent all other rollbacks
04108             $transaction1->rollback(new Exception('test'));
04109         } catch (Exception $e) {
04110             $this->assertEqual(get_class($e), 'Exception');
04111         }
04112         try {
04113             $transaction2->rollback(new Exception('test'));
04114         } catch (Exception $e) {
04115             $this->assertEqual(get_class($e), 'Exception');
04116         }
04117         try {
04118             $transaction1->rollback(new Exception('test'));
04119         } catch (Exception $e) {
04120             // the rollback was used already once, no way to use it again
04121             $this->assertEqual(get_class($e), 'dml_transaction_exception');
04122         }
04123         // this is done in default exception handler usually
04124         $this->assertTrue($DB->is_transaction_started());
04125         $DB->force_transaction_rollback();
04126         $DB->delete_records($tablename);
04127 
04128 
04129         // unknown transaction object
04130         $transaction1 = $DB->start_delegated_transaction();
04131         $data = (object)array('course'=>3);
04132         $DB->insert_record($tablename, $data);
04133         $transaction2 = new moodle_transaction($DB);
04134         try {
04135             $transaction2->allow_commit();
04136             $this->fail('foreign transaction must fail');
04137         } catch (Exception $e) {
04138             $this->assertEqual(get_class($e), 'dml_transaction_exception');
04139         }
04140         try {
04141             $transaction1->allow_commit();
04142             $this->fail('first wrong commit forces rollback');
04143         } catch (Exception $e) {
04144             $this->assertEqual(get_class($e), 'dml_transaction_exception');
04145         }
04146         $DB->force_transaction_rollback();
04147         $DB->delete_records($tablename);
04148     }
04149 
04150     function test_concurent_transactions() {
04151         // Notes about this test:
04152         // 1- MySQL needs to use one engine with transactions support (InnoDB).
04153         // 2- MSSQL needs to have enabled versioning for read committed
04154         //    transactions (ALTER DATABASE xxx SET READ_COMMITTED_SNAPSHOT ON)
04155         $DB = $this->tdb;
04156         $dbman = $DB->get_manager();
04157 
04158         $table = $this->get_test_table();
04159         $tablename = $table->getName();
04160 
04161         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
04162         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
04163         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
04164         $dbman->create_table($table);
04165 
04166         $transaction = $DB->start_delegated_transaction();
04167         $data = (object)array('course'=>1);
04168         $this->assertEqual(0, $DB->count_records($tablename));
04169         $DB->insert_record($tablename, $data);
04170         $this->assertEqual(1, $DB->count_records($tablename));
04171 
04172         //open second connection
04173         $cfg = $DB->export_dbconfig();
04174         if (!isset($cfg->dboptions)) {
04175             $cfg->dboptions = array();
04176         }
04177         $DB2 = moodle_database::get_driver_instance($cfg->dbtype, $cfg->dblibrary);
04178         $DB2->connect($cfg->dbhost, $cfg->dbuser, $cfg->dbpass, $cfg->dbname, $cfg->prefix, $cfg->dboptions);
04179 
04180         // second instance should not see pending inserts
04181         $this->assertEqual(0, $DB2->count_records($tablename));
04182         $data = (object)array('course'=>2);
04183         $DB2->insert_record($tablename, $data);
04184         $this->assertEqual(1, $DB2->count_records($tablename));
04185 
04186         // first should see the changes done from second
04187         $this->assertEqual(2, $DB->count_records($tablename));
04188 
04189         // now commit and we should see it finally in second connections
04190         $transaction->allow_commit();
04191         $this->assertEqual(2, $DB2->count_records($tablename));
04192 
04193         // let's try delete all is also working on (this checks MDL-29198)
04194         // initially both connections see all the records in the table (2)
04195         $this->assertEqual(2, $DB->count_records($tablename));
04196         $this->assertEqual(2, $DB2->count_records($tablename));
04197         $transaction = $DB->start_delegated_transaction();
04198 
04199         // delete all from within transaction
04200         $DB->delete_records($tablename);
04201 
04202         // transactional $DB, sees 0 records now
04203         $this->assertEqual(0, $DB->count_records($tablename));
04204 
04205         // others ($DB2) get no changes yet
04206         $this->assertEqual(2, $DB2->count_records($tablename));
04207 
04208         // now commit and we should see changes
04209         $transaction->allow_commit();
04210         $this->assertEqual(0, $DB2->count_records($tablename));
04211 
04212         $DB2->dispose();
04213     }
04214 
04215     public function test_session_locks() {
04216         $DB = $this->tdb;
04217         $dbman = $DB->get_manager();
04218 
04219         // Open second connection
04220         $cfg = $DB->export_dbconfig();
04221         if (!isset($cfg->dboptions)) {
04222             $cfg->dboptions = array();
04223         }
04224         $DB2 = moodle_database::get_driver_instance($cfg->dbtype, $cfg->dblibrary);
04225         $DB2->connect($cfg->dbhost, $cfg->dbuser, $cfg->dbpass, $cfg->dbname, $cfg->prefix, $cfg->dboptions);
04226 
04227         // Testing that acquiring a lock efectively locks
04228         // Get a session lock on connection1
04229         $rowid = rand(100, 200);
04230         $timeout = 1;
04231         $DB->get_session_lock($rowid, $timeout);
04232 
04233         // Try to get the same session lock on connection2
04234         try {
04235             $DB2->get_session_lock($rowid, $timeout);
04236             $DB2->release_session_lock($rowid); // Should not be excuted, but here for safety
04237             $this->fail('An Exception is missing, expected due to session lock acquired.');
04238         } catch (exception $e) {
04239             $this->assertTrue($e instanceof dml_sessionwait_exception);
04240             $DB->release_session_lock($rowid); // Release lock on connection1
04241         }
04242 
04243         // Testing that releasing a lock efectively frees
04244         // Get a session lock on connection1
04245         $rowid = rand(100, 200);
04246         $timeout = 1;
04247         $DB->get_session_lock($rowid, $timeout);
04248         // Release the lock on connection1
04249         $DB->release_session_lock($rowid);
04250 
04251         // Get the just released lock on connection2
04252         $DB2->get_session_lock($rowid, $timeout);
04253         // Release the lock on connection2
04254         $DB2->release_session_lock($rowid);
04255 
04256         $DB2->dispose();
04257     }
04258 
04259     public function test_bound_param_types() {
04260         $DB = $this->tdb;
04261         $dbman = $DB->get_manager();
04262 
04263         $table = $this->get_test_table();
04264         $tablename = $table->getName();
04265 
04266         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
04267         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
04268         $table->add_field('content', XMLDB_TYPE_TEXT, 'big', XMLDB_UNSIGNED, XMLDB_NOTNULL);
04269         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
04270         $dbman->create_table($table);
04271 
04272         $this->assertTrue($DB->insert_record($tablename, array('name' => '1', 'content'=>'xx')));
04273         $this->assertTrue($DB->insert_record($tablename, array('name' => 2, 'content'=>'yy')));
04274         $this->assertTrue($DB->insert_record($tablename, array('name' => 'somestring', 'content'=>'zz')));
04275         $this->assertTrue($DB->insert_record($tablename, array('name' => 'aa', 'content'=>'1')));
04276         $this->assertTrue($DB->insert_record($tablename, array('name' => 'bb', 'content'=>2)));
04277         $this->assertTrue($DB->insert_record($tablename, array('name' => 'cc', 'content'=>'sometext')));
04278 
04279 
04280         // Conditions in CHAR columns
04281         $this->assertTrue($DB->record_exists($tablename, array('name'=>1)));
04282         $this->assertTrue($DB->record_exists($tablename, array('name'=>'1')));
04283         $this->assertFalse($DB->record_exists($tablename, array('name'=>111)));
04284         $this->assertTrue($DB->get_record($tablename, array('name'=>1)));
04285         $this->assertTrue($DB->get_record($tablename, array('name'=>'1')));
04286         $this->assertFalse($DB->get_record($tablename, array('name'=>111)));
04287         $sqlqm = "SELECT *
04288                     FROM {{$tablename}}
04289                    WHERE name = ?";
04290         $this->assertTrue($records = $DB->get_records_sql($sqlqm, array(1)));
04291         $this->assertEqual(1, count($records));
04292         $this->assertTrue($records = $DB->get_records_sql($sqlqm, array('1')));
04293         $this->assertEqual(1, count($records));
04294         $records = $DB->get_records_sql($sqlqm, array(222));
04295         $this->assertEqual(0, count($records));
04296         $sqlnamed = "SELECT *
04297                        FROM {{$tablename}}
04298                       WHERE name = :name";
04299         $this->assertTrue($records = $DB->get_records_sql($sqlnamed, array('name' => 2)));
04300         $this->assertEqual(1, count($records));
04301         $this->assertTrue($records = $DB->get_records_sql($sqlnamed, array('name' => '2')));
04302         $this->assertEqual(1, count($records));
04303 
04304         // Conditions in TEXT columns always must be performed with the sql_compare_text
04305         // helper function on both sides of the condition
04306         $sqlqm = "SELECT *
04307                     FROM {{$tablename}}
04308                    WHERE " . $DB->sql_compare_text('content') . " =  " . $DB->sql_compare_text('?');
04309         $this->assertTrue($records = $DB->get_records_sql($sqlqm, array('1')));
04310         $this->assertEqual(1, count($records));
04311         $this->assertTrue($records = $DB->get_records_sql($sqlqm, array(1)));
04312         $this->assertEqual(1, count($records));
04313         $sqlnamed = "SELECT *
04314                        FROM {{$tablename}}
04315                       WHERE " . $DB->sql_compare_text('content') . " =  " . $DB->sql_compare_text(':content');
04316         $this->assertTrue($records = $DB->get_records_sql($sqlnamed, array('content' => 2)));
04317         $this->assertEqual(1, count($records));
04318         $this->assertTrue($records = $DB->get_records_sql($sqlnamed, array('content' => '2')));
04319         $this->assertEqual(1, count($records));
04320     }
04321 
04322     public function test_bound_param_reserved() {
04323         $DB = $this->tdb;
04324         $dbman = $DB->get_manager();
04325 
04326         $table = $this->get_test_table();
04327         $tablename = $table->getName();
04328 
04329         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
04330         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
04331         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
04332         $dbman->create_table($table);
04333 
04334         $DB->insert_record($tablename, array('course' => '1'));
04335 
04336         // make sure reserved words do not cause fatal problems in query parameters
04337 
04338         $DB->execute("UPDATE {{$tablename}} SET course = 1 WHERE ID = :select", array('select'=>1));
04339         $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE course = :select", array('select'=>1));
04340         $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} WHERE course = :select", array('select'=>1));
04341         $rs->close();
04342         $DB->get_fieldset_sql("SELECT id FROM {{$tablename}} WHERE course = :select", array('select'=>1));
04343         $DB->set_field_select($tablename, 'course', '1', "id = :select", array('select'=>1));
04344         $DB->delete_records_select($tablename, "id = :select", array('select'=>1));
04345     }
04346 
04347     public function test_limits_and_offsets() {
04348         $DB = $this->tdb;
04349         $dbman = $DB->get_manager();
04350 
04351         if (false) $DB = new moodle_database ();
04352 
04353         $table = $this->get_test_table();
04354         $tablename = $table->getName();
04355 
04356         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
04357         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
04358         $table->add_field('content', XMLDB_TYPE_TEXT, 'big', XMLDB_UNSIGNED, XMLDB_NOTNULL);
04359         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
04360         $dbman->create_table($table);
04361 
04362         $this->assertTrue($DB->insert_record($tablename, array('name' => 'a', 'content'=>'one')));
04363         $this->assertTrue($DB->insert_record($tablename, array('name' => 'b', 'content'=>'two')));
04364         $this->assertTrue($DB->insert_record($tablename, array('name' => 'c', 'content'=>'three')));
04365         $this->assertTrue($DB->insert_record($tablename, array('name' => 'd', 'content'=>'four')));
04366         $this->assertTrue($DB->insert_record($tablename, array('name' => 'e', 'content'=>'five')));
04367         $this->assertTrue($DB->insert_record($tablename, array('name' => 'f', 'content'=>'six')));
04368 
04369         $sqlqm = "SELECT *
04370                     FROM {{$tablename}}";
04371         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 4));
04372         $this->assertEqual(2, count($records));
04373         $this->assertEqual('e', reset($records)->name);
04374         $this->assertEqual('f', end($records)->name);
04375 
04376         $sqlqm = "SELECT *
04377                     FROM {{$tablename}}";
04378         $this->assertFalse($records = $DB->get_records_sql($sqlqm, null, 8));
04379 
04380         $sqlqm = "SELECT *
04381                     FROM {{$tablename}}";
04382         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 0, 4));
04383         $this->assertEqual(4, count($records));
04384         $this->assertEqual('a', reset($records)->name);
04385         $this->assertEqual('d', end($records)->name);
04386 
04387         $sqlqm = "SELECT *
04388                     FROM {{$tablename}}";
04389         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 0, 8));
04390         $this->assertEqual(6, count($records));
04391         $this->assertEqual('a', reset($records)->name);
04392         $this->assertEqual('f', end($records)->name);
04393 
04394         $sqlqm = "SELECT *
04395                     FROM {{$tablename}}";
04396         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 1, 4));
04397         $this->assertEqual(4, count($records));
04398         $this->assertEqual('b', reset($records)->name);
04399         $this->assertEqual('e', end($records)->name);
04400 
04401         $sqlqm = "SELECT *
04402                     FROM {{$tablename}}";
04403         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 4, 4));
04404         $this->assertEqual(2, count($records));
04405         $this->assertEqual('e', reset($records)->name);
04406         $this->assertEqual('f', end($records)->name);
04407 
04408         $sqlqm = "SELECT t.*, t.name AS test
04409                     FROM {{$tablename}} t
04410                     ORDER BY t.id ASC";
04411         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 4, 4));
04412         $this->assertEqual(2, count($records));
04413         $this->assertEqual('e', reset($records)->name);
04414         $this->assertEqual('f', end($records)->name);
04415 
04416         $sqlqm = "SELECT DISTINCT t.name, t.name AS test
04417                     FROM {{$tablename}} t
04418                     ORDER BY t.name DESC";
04419         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 4, 4));
04420         $this->assertEqual(2, count($records));
04421         $this->assertEqual('b', reset($records)->name);
04422         $this->assertEqual('a', end($records)->name);
04423 
04424         $sqlqm = "SELECT 1
04425                     FROM {{$tablename}} t
04426                     WHERE t.name = 'a'";
04427         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 0, 1));
04428         $this->assertEqual(1, count($records));
04429 
04430         $sqlqm = "SELECT 'constant'
04431                     FROM {{$tablename}} t
04432                     WHERE t.name = 'a'";
04433         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 0, 8));
04434         $this->assertEqual(1, count($records));
04435 
04436         $this->assertTrue($DB->insert_record($tablename, array('name' => 'a', 'content'=>'one')));
04437         $this->assertTrue($DB->insert_record($tablename, array('name' => 'b', 'content'=>'two')));
04438         $this->assertTrue($DB->insert_record($tablename, array('name' => 'c', 'content'=>'three')));
04439 
04440         $sqlqm = "SELECT t.name, COUNT(DISTINCT t2.id) AS count, 'Test' AS teststring
04441                     FROM {{$tablename}} t
04442                     LEFT JOIN (
04443                         SELECT t.id, t.name
04444                         FROM {{$tablename}} t
04445                     ) t2 ON t2.name = t.name
04446                     GROUP BY t.name
04447                     ORDER BY t.name ASC";
04448         $this->assertTrue($records = $DB->get_records_sql($sqlqm));
04449         $this->assertEqual(6, count($records));         // a,b,c,d,e,f
04450         $this->assertEqual(2, reset($records)->count);  // a has 2 records now
04451         $this->assertEqual(1, end($records)->count);    // f has 1 record still
04452 
04453         $this->assertTrue($records = $DB->get_records_sql($sqlqm, null, 0, 2));
04454         $this->assertEqual(2, count($records));
04455         $this->assertEqual(2, reset($records)->count);
04456         $this->assertEqual(2, end($records)->count);
04457     }
04458 }
04459 
04465 class moodle_database_for_testing extends moodle_database {
04466     protected $prefix = 'mdl_';
04467 
04468     public function public_fix_table_names($sql) {
04469         return $this->fix_table_names($sql);
04470     }
04471 
04472     public function driver_installed(){}
04473     public function get_dbfamily(){}
04474     protected function get_dbtype(){}
04475     protected function get_dblibrary(){}
04476     public function get_name(){}
04477     public function get_configuration_help(){}
04478     public function get_configuration_hints(){}
04479     public function connect($dbhost, $dbuser, $dbpass, $dbname, $prefix, array $dboptions=null){}
04480     public function get_server_info(){}
04481     protected function allowed_param_types(){}
04482     public function get_last_error(){}
04483     public function get_tables($usecache=true){}
04484     public function get_indexes($table){}
04485     public function get_columns($table, $usecache=true){}
04486     protected function normalise_value($column, $value){}
04487     public function set_debug($state){}
04488     public function get_debug(){}
04489     public function set_logging($state){}
04490     public function change_database_structure($sql){}
04491     public function execute($sql, array $params=null){}
04492     public function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0){}
04493     public function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnum=0){}
04494     public function get_fieldset_sql($sql, array $params=null){}
04495     public function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false){}
04496     public function insert_record($table, $dataobject, $returnid=true, $bulk=false){}
04497     public function import_record($table, $dataobject){}
04498     public function update_record_raw($table, $params, $bulk=false){}
04499     public function update_record($table, $dataobject, $bulk=false){}
04500     public function set_field_select($table, $newfield, $newvalue, $select, array $params=null){}
04501     public function delete_records_select($table, $select, array $params=null){}
04502     public function sql_concat(){}
04503     public function sql_concat_join($separator="' '", $elements=array()){}
04504     public function sql_substr($expr, $start, $length=false){}
04505     public function begin_transaction() {}
04506     public function commit_transaction() {}
04507     public function rollback_transaction() {}
04508 }
 All Data Structures Namespaces Files Functions Variables Enumerations