MDL-30147 dml - added some tests demoing bad get_columns() behavior
[moodle.git] / lib / dml / simpletest / testdml.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * @package    core
20  * @subpackage dml
21  * @copyright  2008 Petr Skoda (http://skodak.org)
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 class dml_test extends UnitTestCase {
28     private $tables = array();
29     /** @var moodle_database */
30     private $tdb;
31     private $data;
32     public  static $includecoverage = array('lib/dml');
33     public  static $excludecoverage = array('lib/dml/simpletest');
35     protected $olddebug;
36     protected $olddisplay;
38     function setUp() {
39         global $DB, $UNITTEST;
41         if (isset($UNITTEST->func_test_db)) {
42             $this->tdb = $UNITTEST->func_test_db;
43         } else {
44             $this->tdb = $DB;
45         }
46     }
48     function tearDown() {
49         $dbman = $this->tdb->get_manager();
51         foreach ($this->tables as $tablename) {
52             if ($dbman->table_exists($tablename)) {
53                 $table = new xmldb_table($tablename);
54                 $dbman->drop_table($table);
55             }
56         }
57         $this->tables = array();
58     }
60     /**
61      * Get a xmldb_table object for testing, deleting any existing table
62      * of the same name, for example if one was left over from a previous test
63      * run that crashed.
64      *
65      * @param database_manager $dbman the database_manager to use.
66      * @param string $suffix table name suffix, use if you need more test tables
67      * @return xmldb_table the table object.
68      */
69     private function get_test_table($suffix = '') {
70         $dbman = $this->tdb->get_manager();
72         $tablename = "unit_table";
73         if ($suffix !== '') {
74             $tablename .= $suffix;
75         }
77         $table = new xmldb_table($tablename);
78         if ($dbman->table_exists($table)) {
79             $dbman->drop_table($table);
80         }
81         $table->setComment("This is a test'n drop table. You can drop it safely");
82         $this->tables[$tablename] = $tablename;
83         return new xmldb_table($tablename);
84     }
86     protected function enable_debugging() {
87         global $CFG;
89         $this->olddebug   = $CFG->debug;       // Save current debug settings
90         $this->olddisplay = $CFG->debugdisplay;
91         $CFG->debug = DEBUG_DEVELOPER;
92         $CFG->debugdisplay = true;
93         ob_start(); // hide debug warning
95     }
97     protected function get_debugging() {
98         global $CFG;
100         $debuginfo = ob_get_contents();
101         ob_end_clean();
102         $CFG->debug = $this->olddebug;         // Restore original debug settings
103         $CFG->debugdisplay = $this->olddisplay;
105         return $debuginfo;
106     }
108     // NOTE: please keep order of test methods here matching the order of moodle_database class methods
110     function test_diagnose() {
111         $DB = $this->tdb;
112         $result = $DB->diagnose();
113         $this->assertNull($result, 'Database self diagnostics failed %s');
114     }
116     function test_get_server_info() {
117         $DB = $this->tdb;
118         $result = $DB->get_server_info();
119         $this->assertTrue(is_array($result));
120         $this->assertTrue(array_key_exists('description', $result));
121         $this->assertTrue(array_key_exists('version', $result));
122     }
124     public function test_get_in_or_equal() {
125         $DB = $this->tdb;
127         // SQL_PARAMS_QM - IN or =
129         // Correct usage of multiple values
130         $in_values = array('value1', 'value2', '3', 4, null, false, true);
131         list($usql, $params) = $DB->get_in_or_equal($in_values);
132         $this->assertEqual('IN ('.implode(',',array_fill(0, count($in_values), '?')).')', $usql);
133         $this->assertEqual(count($in_values), count($params));
134         foreach ($params as $key => $value) {
135             $this->assertIdentical($in_values[$key], $value);
136         }
138         // Correct usage of single value (in an array)
139         $in_values = array('value1');
140         list($usql, $params) = $DB->get_in_or_equal($in_values);
141         $this->assertEqual("= ?", $usql);
142         $this->assertEqual(1, count($params));
143         $this->assertEqual($in_values[0], $params[0]);
145         // Correct usage of single value
146         $in_value = 'value1';
147         list($usql, $params) = $DB->get_in_or_equal($in_values);
148         $this->assertEqual("= ?", $usql);
149         $this->assertEqual(1, count($params));
150         $this->assertEqual($in_value, $params[0]);
152         // SQL_PARAMS_QM - NOT IN or <>
154         // Correct usage of multiple values
155         $in_values = array('value1', 'value2', 'value3', 'value4');
156         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
157         $this->assertEqual("NOT IN (?,?,?,?)", $usql);
158         $this->assertEqual(4, count($params));
159         foreach ($params as $key => $value) {
160             $this->assertEqual($in_values[$key], $value);
161         }
163         // Correct usage of single value (in array()
164         $in_values = array('value1');
165         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
166         $this->assertEqual("<> ?", $usql);
167         $this->assertEqual(1, count($params));
168         $this->assertEqual($in_values[0], $params[0]);
170         // Correct usage of single value
171         $in_value = 'value1';
172         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
173         $this->assertEqual("<> ?", $usql);
174         $this->assertEqual(1, count($params));
175         $this->assertEqual($in_value, $params[0]);
177         // SQL_PARAMS_NAMED - IN or =
179         // Correct usage of multiple values
180         $in_values = array('value1', 'value2', 'value3', 'value4');
181         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
182         $this->assertEqual(4, count($params));
183         reset($in_values);
184         $ps = array();
185         foreach ($params as $key => $value) {
186             $this->assertEqual(current($in_values), $value);
187             next($in_values);
188             $ps[] = ':'.$key;
189         }
190         $this->assertEqual("IN (".implode(',', $ps).")", $usql);
192         // Correct usage of single values (in array)
193         $in_values = array('value1');
194         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
195         $this->assertEqual(1, count($params));
196         $value = reset($params);
197         $key = key($params);
198         $this->assertEqual("= :$key", $usql);
199         $this->assertEqual($in_value, $value);
201         // Correct usage of single value
202         $in_value = 'value1';
203         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
204         $this->assertEqual(1, count($params));
205         $value = reset($params);
206         $key = key($params);
207         $this->assertEqual("= :$key", $usql);
208         $this->assertEqual($in_value, $value);
210         // SQL_PARAMS_NAMED - NOT IN or <>
212         // Correct usage of multiple values
213         $in_values = array('value1', 'value2', 'value3', 'value4');
214         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
215         $this->assertEqual(4, count($params));
216         reset($in_values);
217         $ps = array();
218         foreach ($params as $key => $value) {
219             $this->assertEqual(current($in_values), $value);
220             next($in_values);
221             $ps[] = ':'.$key;
222         }
223         $this->assertEqual("NOT IN (".implode(',', $ps).")", $usql);
225         // Correct usage of single values (in array)
226         $in_values = array('value1');
227         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
228         $this->assertEqual(1, count($params));
229         $value = reset($params);
230         $key = key($params);
231         $this->assertEqual("<> :$key", $usql);
232         $this->assertEqual($in_value, $value);
234         // Correct usage of single value
235         $in_value = 'value1';
236         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
237         $this->assertEqual(1, count($params));
238         $value = reset($params);
239         $key = key($params);
240         $this->assertEqual("<> :$key", $usql);
241         $this->assertEqual($in_value, $value);
243         // make sure the param names are unique
244         list($usql1, $params1) = $DB->get_in_or_equal(array(1,2,3), SQL_PARAMS_NAMED, 'param');
245         list($usql2, $params2) = $DB->get_in_or_equal(array(1,2,3), SQL_PARAMS_NAMED, 'param');
246         $params1 = array_keys($params1);
247         $params2 = array_keys($params2);
248         $common = array_intersect($params1, $params2);
249         $this->assertEqual(count($common), 0);
251         // Some incorrect tests
253         // Incorrect usage passing not-allowed params type
254         $in_values = array(1, 2, 3);
255         try {
256             list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_DOLLAR, 'param', false);
257             $this->fail('An Exception is missing, expected due to not supported SQL_PARAMS_DOLLAR');
258         } catch (exception $e) {
259             $this->assertTrue($e instanceof dml_exception);
260             $this->assertEqual($e->errorcode, 'typenotimplement');
261         }
263         // Incorrect usage passing empty array
264         $in_values = array();
265         try {
266             list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
267             $this->fail('An Exception is missing, expected due to empty array of items');
268         } catch (exception $e) {
269             $this->assertTrue($e instanceof coding_exception);
270         }
272         // Test using $onemptyitems
274         // Correct usage passing empty array and $onemptyitems = NULL (equal = true, QM)
275         $in_values = array();
276         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, NULL);
277         $this->assertEqual(' IS NULL', $usql);
278         $this->assertIdentical(array(), $params);
280         // Correct usage passing empty array and $onemptyitems = NULL (equal = false, NAMED)
281         $in_values = array();
282         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, NULL);
283         $this->assertEqual(' IS NOT NULL', $usql);
284         $this->assertIdentical(array(), $params);
286         // Correct usage passing empty array and $onemptyitems = true (equal = true, QM)
287         $in_values = array();
288         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, true);
289         $this->assertEqual('= ?', $usql);
290         $this->assertIdentical(array(true), $params);
292         // Correct usage passing empty array and $onemptyitems = true (equal = false, NAMED)
293         $in_values = array();
294         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, true);
295         $this->assertEqual(1, count($params));
296         $value = reset($params);
297         $key = key($params);
298         $this->assertEqual('<> :'.$key, $usql);
299         $this->assertIdentical($value, true);
301         // Correct usage passing empty array and $onemptyitems = -1 (equal = true, QM)
302         $in_values = array();
303         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, -1);
304         $this->assertEqual('= ?', $usql);
305         $this->assertIdentical(array(-1), $params);
307         // Correct usage passing empty array and $onemptyitems = -1 (equal = false, NAMED)
308         $in_values = array();
309         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, -1);
310         $this->assertEqual(1, count($params));
311         $value = reset($params);
312         $key = key($params);
313         $this->assertEqual('<> :'.$key, $usql);
314         $this->assertIdentical($value, -1);
316         // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = true, QM)
317         $in_values = array();
318         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, 'onevalue');
319         $this->assertEqual('= ?', $usql);
320         $this->assertIdentical(array('onevalue'), $params);
322         // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = false, NAMED)
323         $in_values = array();
324         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, 'onevalue');
325         $this->assertEqual(1, count($params));
326         $value = reset($params);
327         $key = key($params);
328         $this->assertEqual('<> :'.$key, $usql);
329         $this->assertIdentical($value, 'onevalue');
330     }
332     public function test_fix_table_names() {
333         $DB = new moodle_database_for_testing();
334         $prefix = $DB->get_prefix();
336         // Simple placeholder
337         $placeholder = "{user_123}";
338         $this->assertIdentical($prefix."user_123", $DB->public_fix_table_names($placeholder));
340         // wrong table name
341         $placeholder = "{user-a}";
342         $this->assertIdentical($placeholder, $DB->public_fix_table_names($placeholder));
344         // wrong table name
345         $placeholder = "{123user}";
346         $this->assertIdentical($placeholder, $DB->public_fix_table_names($placeholder));
348         // Full SQL
349         $sql = "SELECT * FROM {user}, {funny_table_name}, {mdl_stupid_table} WHERE {user}.id = {funny_table_name}.userid";
350         $expected = "SELECT * FROM {$prefix}user, {$prefix}funny_table_name, {$prefix}mdl_stupid_table WHERE {$prefix}user.id = {$prefix}funny_table_name.userid";
351         $this->assertIdentical($expected, $DB->public_fix_table_names($sql));
352     }
354     function test_fix_sql_params() {
355         $DB = $this->tdb;
357         $table = $this->get_test_table();
358         $tablename = $table->getName();
360         // Correct table placeholder substitution
361         $sql = "SELECT * FROM {{$tablename}}";
362         $sqlarray = $DB->fix_sql_params($sql);
363         $this->assertEqual("SELECT * FROM {$DB->get_prefix()}".$tablename, $sqlarray[0]);
365         // Conversions of all param types
366         $sql = array();
367         $sql[SQL_PARAMS_NAMED]  = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = :param1, course = :param2";
368         $sql[SQL_PARAMS_QM]     = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = ?, course = ?";
369         $sql[SQL_PARAMS_DOLLAR] = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = \$1, course = \$2";
371         $params = array();
372         $params[SQL_PARAMS_NAMED]  = array('param1'=>'first record', 'param2'=>1);
373         $params[SQL_PARAMS_QM]     = array('first record', 1);
374         $params[SQL_PARAMS_DOLLAR] = array('first record', 1);
376         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_NAMED], $params[SQL_PARAMS_NAMED]);
377         $this->assertIdentical($rsql, $sql[$rtype]);
378         $this->assertIdentical($rparams, $params[$rtype]);
380         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_QM], $params[SQL_PARAMS_QM]);
381         $this->assertIdentical($rsql, $sql[$rtype]);
382         $this->assertIdentical($rparams, $params[$rtype]);
384         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_DOLLAR], $params[SQL_PARAMS_DOLLAR]);
385         $this->assertIdentical($rsql, $sql[$rtype]);
386         $this->assertIdentical($rparams, $params[$rtype]);
389         // Malformed table placeholder
390         $sql = "SELECT * FROM [testtable]";
391         $sqlarray = $DB->fix_sql_params($sql);
392         $this->assertIdentical($sql, $sqlarray[0]);
395         // Mixed param types (colon and dollar)
396         $sql = "SELECT * FROM {{$tablename}} WHERE name = :param1, course = \$1";
397         $params = array('param1' => 'record1', 'param2' => 3);
398         try {
399             $DB->fix_sql_params($sql, $params);
400             $this->fail("Expecting an exception, none occurred");
401         } catch (Exception $e) {
402             $this->assertTrue($e instanceof dml_exception);
403         }
405         // Mixed param types (question and dollar)
406         $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = \$1";
407         $params = array('param1' => 'record2', 'param2' => 5);
408         try {
409             $DB->fix_sql_params($sql, $params);
410             $this->fail("Expecting an exception, none occurred");
411         } catch (Exception $e) {
412             $this->assertTrue($e instanceof dml_exception);
413         }
415         // Too few params in sql
416         $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = ?, id = ?";
417         $params = array('record2', 3);
418         try {
419             $DB->fix_sql_params($sql, $params);
420             $this->fail("Expecting an exception, none occurred");
421         } catch (Exception $e) {
422             $this->assertTrue($e instanceof dml_exception);
423         }
425         // Too many params in array: no error, just use what is necessary
426         $params[] = 1;
427         $params[] = time();
428         try {
429             $sqlarray = $DB->fix_sql_params($sql, $params);
430             $this->assertTrue(is_array($sqlarray));
431             $this->assertEqual(count($sqlarray[1]), 3);
432         } catch (Exception $e) {
433             $this->fail("Unexpected ".get_class($e)." exception");
434         }
436         // Named params missing from array
437         $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
438         $params = array('wrongname' => 'record1', 'course' => 1);
439         try {
440             $DB->fix_sql_params($sql, $params);
441             $this->fail("Expecting an exception, none occurred");
442         } catch (Exception $e) {
443             $this->assertTrue($e instanceof dml_exception);
444         }
446         // Duplicate named param in query - this is a very important feature!!
447         // it helps with debugging of sloppy code
448         $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :name";
449         $params = array('name' => 'record2', 'course' => 3);
450         try {
451             $DB->fix_sql_params($sql, $params);
452             $this->fail("Expecting an exception, none occurred");
453         } catch (Exception $e) {
454             $this->assertTrue($e instanceof dml_exception);
455         }
457         // Extra named param is ignored
458         $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
459         $params = array('name' => 'record1', 'course' => 1, 'extrastuff'=>'haha');
460         try {
461             $sqlarray = $DB->fix_sql_params($sql, $params);
462             $this->assertTrue(is_array($sqlarray));
463             $this->assertEqual(count($sqlarray[1]), 2);
464         } catch (Exception $e) {
465             $this->fail("Unexpected ".get_class($e)." exception");
466         }
468         // Params exceeding 30 chars length
469         $sql = "SELECT * FROM {{$tablename}} WHERE name = :long_placeholder_with_more_than_30";
470         $params = array('long_placeholder_with_more_than_30' => 'record1');
471         try {
472             $DB->fix_sql_params($sql, $params);
473             $this->fail("Expecting an exception, none occurred");
474         } catch (Exception $e) {
475             $this->assertTrue($e instanceof coding_exception);
476         }
478         // Booleans in NAMED params are casting to 1/0 int
479         $sql = "SELECT * FROM {{$tablename}} WHERE course = ? OR course = ?";
480         $params = array(true, false);
481         list($sql, $params) = $DB->fix_sql_params($sql, $params);
482         $this->assertTrue(reset($params) === 1);
483         $this->assertTrue(next($params) === 0);
485         // Booleans in QM params are casting to 1/0 int
486         $sql = "SELECT * FROM {{$tablename}} WHERE course = :course1 OR course = :course2";
487         $params = array('course1' => true, 'course2' => false);
488         list($sql, $params) = $DB->fix_sql_params($sql, $params);
489         $this->assertTrue(reset($params) === 1);
490         $this->assertTrue(next($params) === 0);
492         // Booleans in DOLLAR params are casting to 1/0 int
493         $sql = "SELECT * FROM {{$tablename}} WHERE course = \$1 OR course = \$2";
494         $params = array(true, false);
495         list($sql, $params) = $DB->fix_sql_params($sql, $params);
496         $this->assertTrue(reset($params) === 1);
497         $this->assertTrue(next($params) === 0);
499         // No data types are touched except bool
500         $sql = "SELECT * FROM {{$tablename}} WHERE name IN (?,?,?,?,?,?)";
501         $inparams = array('abc', 'ABC', NULL, '1', 1, 1.4);
502         list($sql, $params) = $DB->fix_sql_params($sql, $inparams);
503         $this->assertIdentical(array_values($params), array_values($inparams));
504     }
506     public function test_strtok() {
507         // strtok was previously used by bound emulation, make sure it is not used any more
508         $DB = $this->tdb;
509         $dbman = $this->tdb->get_manager();
511         $table = $this->get_test_table();
512         $tablename = $table->getName();
514         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
515         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
516         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
517         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
518         $dbman->create_table($table);
520         $str = 'a?b?c?d';
521         $this->assertIdentical(strtok($str, '?'), 'a');
523         $DB->get_records($tablename, array('id'=>1));
525         $this->assertIdentical(strtok('?'), 'b');
526     }
528     public function test_tweak_param_names() {
529         // Note the tweak_param_names() method is only available in the oracle driver,
530         // hence we look for expected results indirectly, by testing various DML methods
531         // with some "extreme" conditions causing the tweak to happen.
532         $DB = $this->tdb;
533         $dbman = $this->tdb->get_manager();
535         $table = $this->get_test_table();
536         $tablename = $table->getName();
538         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
539         // Add some columns with 28 chars in the name
540         $table->add_field('long_int_columnname_with_28c', XMLDB_TYPE_INTEGER, '10');
541         $table->add_field('long_dec_columnname_with_28c', XMLDB_TYPE_NUMBER, '10,2');
542         $table->add_field('long_str_columnname_with_28c', XMLDB_TYPE_CHAR, '100');
543         // Add some columns with 30 chars in the name
544         $table->add_field('long_int_columnname_with_30cxx', XMLDB_TYPE_INTEGER, '10');
545         $table->add_field('long_dec_columnname_with_30cxx', XMLDB_TYPE_NUMBER, '10,2');
546         $table->add_field('long_str_columnname_with_30cxx', XMLDB_TYPE_CHAR, '100');
548         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
550         $dbman->create_table($table);
552         $this->assertTrue($dbman->table_exists($tablename));
554         // Test insert record
555         $rec1 = new stdClass();
556         $rec1->long_int_columnname_with_28c = 28;
557         $rec1->long_dec_columnname_with_28c = 28.28;
558         $rec1->long_str_columnname_with_28c = '28';
559         $rec1->long_int_columnname_with_30cxx = 30;
560         $rec1->long_dec_columnname_with_30cxx = 30.30;
561         $rec1->long_str_columnname_with_30cxx = '30';
563         // insert_record()
564         $rec1->id = $DB->insert_record($tablename, $rec1);
565         $this->assertEqual($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
567         // update_record()
568         $DB->update_record($tablename, $rec1);
569         $this->assertEqual($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
571         // set_field()
572         $rec1->long_int_columnname_with_28c = 280;
573         $DB->set_field($tablename, 'long_int_columnname_with_28c', $rec1->long_int_columnname_with_28c,
574             array('id' => $rec1->id, 'long_int_columnname_with_28c' => 28));
575         $rec1->long_dec_columnname_with_28c = 280.28;
576         $DB->set_field($tablename, 'long_dec_columnname_with_28c', $rec1->long_dec_columnname_with_28c,
577             array('id' => $rec1->id, 'long_dec_columnname_with_28c' => 28.28));
578         $rec1->long_str_columnname_with_28c = '280';
579         $DB->set_field($tablename, 'long_str_columnname_with_28c', $rec1->long_str_columnname_with_28c,
580             array('id' => $rec1->id, 'long_str_columnname_with_28c' => '28'));
581         $rec1->long_int_columnname_with_30cxx = 300;
582         $DB->set_field($tablename, 'long_int_columnname_with_30cxx', $rec1->long_int_columnname_with_30cxx,
583             array('id' => $rec1->id, 'long_int_columnname_with_30cxx' => 30));
584         $rec1->long_dec_columnname_with_30cxx = 300.30;
585         $DB->set_field($tablename, 'long_dec_columnname_with_30cxx', $rec1->long_dec_columnname_with_30cxx,
586             array('id' => $rec1->id, 'long_dec_columnname_with_30cxx' => 30.30));
587         $rec1->long_str_columnname_with_30cxx = '300';
588         $DB->set_field($tablename, 'long_str_columnname_with_30cxx', $rec1->long_str_columnname_with_30cxx,
589             array('id' => $rec1->id, 'long_str_columnname_with_30cxx' => '30'));
590         $this->assertEqual($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
592         // delete_records()
593         $rec2 = $DB->get_record($tablename, array('id' => $rec1->id));
594         $rec2->id = $DB->insert_record($tablename, $rec2);
595         $this->assertEqual(2, $DB->count_records($tablename));
596         $DB->delete_records($tablename, (array) $rec2);
597         $this->assertEqual(1, $DB->count_records($tablename));
599         // get_recordset()
600         $rs = $DB->get_recordset($tablename, (array) $rec1);
601         $iterations = 0;
602         foreach ($rs as $rec2) {
603             $iterations++;
604         }
605         $rs->close();
606         $this->assertEqual(1, $iterations);
607         $this->assertEqual($rec1, $rec2);
609         // get_records()
610         $recs = $DB->get_records($tablename, (array) $rec1);
611         $this->assertEqual(1, count($recs));
612         $this->assertEqual($rec1, reset($recs));
614         // get_fieldset_select()
615         $select = 'id = :id AND
616                    long_int_columnname_with_28c = :long_int_columnname_with_28c AND
617                    long_dec_columnname_with_28c = :long_dec_columnname_with_28c AND
618                    long_str_columnname_with_28c = :long_str_columnname_with_28c AND
619                    long_int_columnname_with_30cxx = :long_int_columnname_with_30cxx AND
620                    long_dec_columnname_with_30cxx = :long_dec_columnname_with_30cxx AND
621                    long_str_columnname_with_30cxx = :long_str_columnname_with_30cxx';
622         $fields = $DB->get_fieldset_select($tablename, 'long_int_columnname_with_28c', $select, (array)$rec1);
623         $this->assertEqual(1, count($fields));
624         $this->assertEqual($rec1->long_int_columnname_with_28c, reset($fields));
625         $fields = $DB->get_fieldset_select($tablename, 'long_dec_columnname_with_28c', $select, (array)$rec1);
626         $this->assertEqual($rec1->long_dec_columnname_with_28c, reset($fields));
627         $fields = $DB->get_fieldset_select($tablename, 'long_str_columnname_with_28c', $select, (array)$rec1);
628         $this->assertEqual($rec1->long_str_columnname_with_28c, reset($fields));
629         $fields = $DB->get_fieldset_select($tablename, 'long_int_columnname_with_30cxx', $select, (array)$rec1);
630         $this->assertEqual($rec1->long_int_columnname_with_30cxx, reset($fields));
631         $fields = $DB->get_fieldset_select($tablename, 'long_dec_columnname_with_30cxx', $select, (array)$rec1);
632         $this->assertEqual($rec1->long_dec_columnname_with_30cxx, reset($fields));
633         $fields = $DB->get_fieldset_select($tablename, 'long_str_columnname_with_30cxx', $select, (array)$rec1);
634         $this->assertEqual($rec1->long_str_columnname_with_30cxx, reset($fields));
636         // overlapping placeholders (progressive str_replace)
637         $overlapselect = 'id = :p AND
638                    long_int_columnname_with_28c = :param1 AND
639                    long_dec_columnname_with_28c = :param2 AND
640                    long_str_columnname_with_28c = :param_with_29_characters_long AND
641                    long_int_columnname_with_30cxx = :param_with_30_characters_long_ AND
642                    long_dec_columnname_with_30cxx = :param_ AND
643                    long_str_columnname_with_30cxx = :param__';
644         $overlapparams = array(
645                 'p' => $rec1->id,
646                 'param1' => $rec1->long_int_columnname_with_28c,
647                 'param2' => $rec1->long_dec_columnname_with_28c,
648                 'param_with_29_characters_long' => $rec1->long_str_columnname_with_28c,
649                 'param_with_30_characters_long_' => $rec1->long_int_columnname_with_30cxx,
650                 'param_' => $rec1->long_dec_columnname_with_30cxx,
651                 'param__' => $rec1->long_str_columnname_with_30cxx);
652         $recs = $DB->get_records_select($tablename, $overlapselect, $overlapparams);
653         $this->assertEqual(1, count($recs));
654         $this->assertEqual($rec1, reset($recs));
656         // execute()
657         $DB->execute("DELETE FROM {{$tablename}} WHERE $select", (array)$rec1);
658         $this->assertEqual(0, $DB->count_records($tablename));
659     }
661     public function test_get_tables() {
662         $DB = $this->tdb;
663         $dbman = $this->tdb->get_manager();
665         // Need to test with multiple DBs
666         $table = $this->get_test_table();
667         $tablename = $table->getName();
669         $original_count = count($DB->get_tables());
671         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
672         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
674         $dbman->create_table($table);
675         $this->assertTrue(count($DB->get_tables()) == $original_count + 1);
677         $dbman->drop_table($table);
678         $this->assertTrue(count($DB->get_tables()) == $original_count);
679     }
681     public function test_get_indexes() {
682         $DB = $this->tdb;
683         $dbman = $this->tdb->get_manager();
685         $table = $this->get_test_table();
686         $tablename = $table->getName();
688         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
689         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
690         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
691         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
692         $table->add_index('course-id', XMLDB_INDEX_UNIQUE, array('course', 'id'));
693         $dbman->create_table($table);
695         $indices = $DB->get_indexes($tablename);
696         $this->assertTrue(is_array($indices));
697         $this->assertEqual(count($indices), 2);
698         // we do not care about index names for now
699         $first = array_shift($indices);
700         $second = array_shift($indices);
701         if (count($first['columns']) == 2) {
702             $composed = $first;
703             $single   = $second;
704         } else {
705             $composed = $second;
706             $single   = $first;
707         }
708         $this->assertFalse($single['unique']);
709         $this->assertTrue($composed['unique']);
710         $this->assertEqual(1, count($single['columns']));
711         $this->assertEqual(2, count($composed['columns']));
712         $this->assertEqual('course', $single['columns'][0]);
713         $this->assertEqual('course', $composed['columns'][0]);
714         $this->assertEqual('id', $composed['columns'][1]);
715     }
717     public function test_get_columns() {
718         $DB = $this->tdb;
719         $dbman = $this->tdb->get_manager();
721         $table = $this->get_test_table();
722         $tablename = $table->getName();
724         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
725         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
726         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
727         $table->add_field('description', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
728         $table->add_field('enumfield', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'test2');
729         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
730         $table->add_field('onefloat', XMLDB_TYPE_FLOAT, '10,2', null, null, null, 300);
731         $table->add_field('anotherfloat', XMLDB_TYPE_FLOAT, null, null, null, null, 400);
732         $table->add_field('negativedfltint', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '-1');
733         $table->add_field('negativedfltnumber', XMLDB_TYPE_NUMBER, '10', null, XMLDB_NOTNULL, null, '-2');
734         $table->add_field('negativedfltfloat', XMLDB_TYPE_FLOAT, '10', null, XMLDB_NOTNULL, null, '-3');
735         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
736         $dbman->create_table($table);
738         $columns = $DB->get_columns($tablename);
739         $this->assertTrue(is_array($columns));
741         $fields = $table->getFields();
742         $this->assertEqual(count($columns), count($fields));
744         $field = $columns['id'];
745         $this->assertEqual('R', $field->meta_type);
746         $this->assertTrue($field->auto_increment);
747         $this->assertTrue($field->unique);
749         $field = $columns['course'];
750         $this->assertEqual('I', $field->meta_type);
751         $this->assertFalse($field->auto_increment);
752         $this->assertTrue($field->has_default);
753         $this->assertEqual(0, $field->default_value);
754         $this->assertTrue($field->not_null);
756         $field = $columns['name'];
757         $this->assertEqual('C', $field->meta_type);
758         $this->assertFalse($field->auto_increment);
759         $this->assertEqual(255, $field->max_length);
760         $this->assertTrue($field->has_default);
761         $this->assertIdentical('lala', $field->default_value);
762         $this->assertFalse($field->not_null);
764         $field = $columns['description'];
765         $this->assertEqual('X', $field->meta_type);
766         $this->assertFalse($field->auto_increment);
767         $this->assertFalse($field->has_default);
768         $this->assertIdentical(null, $field->default_value);
769         $this->assertFalse($field->not_null);
771         $field = $columns['enumfield'];
772         $this->assertEqual('C', $field->meta_type);
773         $this->assertFalse($field->auto_increment);
774         $this->assertIdentical('test2', $field->default_value);
775         $this->assertTrue($field->not_null);
777         $field = $columns['onenum'];
778         $this->assertEqual('N', $field->meta_type);
779         $this->assertFalse($field->auto_increment);
780         $this->assertEqual(10, $field->max_length);
781         $this->assertEqual(2, $field->scale);
782         $this->assertTrue($field->has_default);
783         $this->assertEqual(200.0, $field->default_value);
784         $this->assertFalse($field->not_null);
786         $field = $columns['onefloat'];
787         $this->assertEqual('N', $field->meta_type);
788         $this->assertFalse($field->auto_increment);
789         $this->assertTrue($field->has_default);
790         $this->assertEqual(300.0, $field->default_value);
791         $this->assertFalse($field->not_null);
793         $field = $columns['anotherfloat'];
794         $this->assertEqual('N', $field->meta_type);
795         $this->assertFalse($field->auto_increment);
796         $this->assertTrue($field->has_default);
797         $this->assertEqual(400.0, $field->default_value);
798         $this->assertFalse($field->not_null);
800         // Test negative defaults in numerical columns
801         $field = $columns['negativedfltint'];
802         $this->assertTrue($field->has_default);
803         $this->assertEqual(-1, $field->default_value);
805         $field = $columns['negativedfltnumber'];
806         $this->assertTrue($field->has_default);
807         $this->assertEqual(-2, $field->default_value);
809         $field = $columns['negativedfltfloat'];
810         $this->assertTrue($field->has_default);
811         $this->assertEqual(-3, $field->default_value);
813         for ($i = 0; $i < count($columns); $i++) {
814             if ($i == 0) {
815                 $next_column = reset($columns);
816                 $next_field  = reset($fields);
817             } else {
818                 $next_column = next($columns);
819                 $next_field  = next($fields);
820             }
822             $this->assertEqual($next_column->name, $next_field->name);
823         }
825         // Test get_columns for non-existing table returns empty array. MDL-30147
826         $columns = $DB->get_columns('xxxx');
827         $this->assertEqual(array(), $columns);
828     }
830     public function test_get_manager() {
831         $DB = $this->tdb;
832         $dbman = $this->tdb->get_manager();
834         $this->assertTrue($dbman instanceof database_manager);
835     }
837     public function test_setup_is_unicodedb() {
838         $DB = $this->tdb;
839         $this->assertTrue($DB->setup_is_unicodedb());
840     }
842     public function test_set_debug() { //tests get_debug() too
843         $DB = $this->tdb;
844         $dbman = $this->tdb->get_manager();
846         $table = $this->get_test_table();
847         $tablename = $table->getName();
849         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
850         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
851         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
852         $dbman->create_table($table);
854         $sql = "SELECT * FROM {{$tablename}}";
856         $prevdebug = $DB->get_debug();
858         ob_start();
859         $DB->set_debug(true);
860         $this->assertTrue($DB->get_debug());
861         $DB->execute($sql);
862         $DB->set_debug(false);
863         $this->assertFalse($DB->get_debug());
864         $debuginfo = ob_get_contents();
865         ob_end_clean();
866         $this->assertFalse($debuginfo === '');
868         ob_start();
869         $DB->execute($sql);
870         $debuginfo = ob_get_contents();
871         ob_end_clean();
872         $this->assertTrue($debuginfo === '');
874         $DB->set_debug($prevdebug);
875     }
877     public function test_execute() {
878         $DB = $this->tdb;
879         $dbman = $this->tdb->get_manager();
881         $table1 = $this->get_test_table('1');
882         $tablename1 = $table1->getName();
883         $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
884         $table1->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
885         $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
886         $table1->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
887         $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
888         $dbman->create_table($table1);
890         $table2 = $this->get_test_table('2');
891         $tablename2 = $table2->getName();
892         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
893         $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
894         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
895         $dbman->create_table($table2);
897         $DB->insert_record($tablename1, array('course' => 3, 'name' => 'aaa'));
898         $DB->insert_record($tablename1, array('course' => 1, 'name' => 'bbb'));
899         $DB->insert_record($tablename1, array('course' => 7, 'name' => 'ccc'));
900         $DB->insert_record($tablename1, array('course' => 3, 'name' => 'ddd'));
902         // select results are ignored
903         $sql = "SELECT * FROM {{$tablename1}} WHERE course = :course";
904         $this->assertTrue($DB->execute($sql, array('course'=>3)));
906         // throw exception on error
907         $sql = "XXUPDATE SET XSSD";
908         try {
909             $DB->execute($sql);
910             $this->fail("Expecting an exception, none occurred");
911         } catch (Exception $e) {
912             $this->assertTrue($e instanceof dml_exception);
913         }
915         // update records
916         $sql = "UPDATE {{$tablename1}}
917                    SET course = 6
918                  WHERE course = ?";
919         $this->assertTrue($DB->execute($sql, array('3')));
920         $this->assertEqual($DB->count_records($tablename1, array('course' => 6)), 2);
922         // insert from one into second table
923         $sql = "INSERT INTO {{$tablename2}} (course)
925                 SELECT course
926                   FROM {{$tablename1}}";
927         $this->assertTrue($DB->execute($sql));
928         $this->assertEqual($DB->count_records($tablename2), 4);
929     }
931     public function test_get_recordset() {
932         $DB = $this->tdb;
933         $dbman = $DB->get_manager();
935         $table = $this->get_test_table();
936         $tablename = $table->getName();
938         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
939         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
940         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
941         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
942         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
943         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
944         $dbman->create_table($table);
946         $data = array(array('id' => 1, 'course' => 3, 'name' => 'record1', 'onetext'=>'abc'),
947                       array('id' => 2, 'course' => 3, 'name' => 'record2', 'onetext'=>'abcd'),
948                       array('id' => 3, 'course' => 5, 'name' => 'record3', 'onetext'=>'abcde'));
950         foreach ($data as $record) {
951             $DB->insert_record($tablename, $record);
952         }
954         // standard recordset iteration
955         $rs = $DB->get_recordset($tablename);
956         $this->assertTrue($rs instanceof moodle_recordset);
957         reset($data);
958         foreach($rs as $record) {
959             $data_record = current($data);
960             foreach ($record as $k => $v) {
961                 $this->assertEqual($data_record[$k], $v);
962             }
963             next($data);
964         }
965         $rs->close();
967         // iterator style usage
968         $rs = $DB->get_recordset($tablename);
969         $this->assertTrue($rs instanceof moodle_recordset);
970         reset($data);
971         while ($rs->valid()) {
972             $record = $rs->current();
973             $data_record = current($data);
974             foreach ($record as $k => $v) {
975                 $this->assertEqual($data_record[$k], $v);
976             }
977             next($data);
978             $rs->next();
979         }
980         $rs->close();
982         // make sure rewind is ignored
983         $rs = $DB->get_recordset($tablename);
984         $this->assertTrue($rs instanceof moodle_recordset);
985         reset($data);
986         $i = 0;
987         foreach($rs as $record) {
988             $i++;
989             $rs->rewind();
990             if ($i > 10) {
991                 $this->fail('revind not ignored in recordsets');
992                 break;
993             }
994             $data_record = current($data);
995             foreach ($record as $k => $v) {
996                 $this->assertEqual($data_record[$k], $v);
997             }
998             next($data);
999         }
1000         $rs->close();
1002         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
1003         $conditions = array('onetext' => '1');
1004         try {
1005             $rs = $DB->get_recordset($tablename, $conditions);
1006             $this->fail('An Exception is missing, expected due to equating of text fields');
1007         } catch (exception $e) {
1008             $this->assertTrue($e instanceof dml_exception);
1009             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
1010         }
1012         // notes:
1013         //  * limits are tested in test_get_recordset_sql()
1014         //  * where_clause() is used internally and is tested in test_get_records()
1015     }
1017     public function test_get_recordset_iterator_keys() {
1018         $DB = $this->tdb;
1019         $dbman = $DB->get_manager();
1021         $table = $this->get_test_table();
1022         $tablename = $table->getName();
1024         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1025         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1026         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
1027         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
1028         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1029         $dbman->create_table($table);
1031         $data = array(array('id'=> 1, 'course' => 3, 'name' => 'record1'),
1032                       array('id'=> 2, 'course' => 3, 'name' => 'record2'),
1033                       array('id'=> 3, 'course' => 5, 'name' => 'record3'));
1034         foreach ($data as $record) {
1035             $DB->insert_record($tablename, $record);
1036         }
1038         // Test repeated numeric keys are returned ok
1039         $rs = $DB->get_recordset($tablename, NULL, NULL, 'course, name, id');
1041         reset($data);
1042         $count = 0;
1043         foreach($rs as $key => $record) {
1044             $data_record = current($data);
1045             $this->assertEqual($data_record['course'], $key);
1046             next($data);
1047             $count++;
1048         }
1049         $rs->close();
1050         $this->assertEqual($count, 3);
1052         // Test string keys are returned ok
1053         $rs = $DB->get_recordset($tablename, NULL, NULL, 'name, course, id');
1055         reset($data);
1056         $count = 0;
1057         foreach($rs as $key => $record) {
1058             $data_record = current($data);
1059             $this->assertEqual($data_record['name'], $key);
1060             next($data);
1061             $count++;
1062         }
1063         $rs->close();
1064         $this->assertEqual($count, 3);
1066         // Test numeric not starting in 1 keys are returned ok
1067         $rs = $DB->get_recordset($tablename, NULL, 'id DESC', 'id, course, name');
1069         $data = array_reverse($data);
1070         reset($data);
1071         $count = 0;
1072         foreach($rs as $key => $record) {
1073             $data_record = current($data);
1074             $this->assertEqual($data_record['id'], $key);
1075             next($data);
1076             $count++;
1077         }
1078         $rs->close();
1079         $this->assertEqual($count, 3);
1080     }
1082     public function test_get_recordset_list() {
1083         $DB = $this->tdb;
1084         $dbman = $DB->get_manager();
1086         $table = $this->get_test_table();
1087         $tablename = $table->getName();
1089         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1090         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1091         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
1092         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1093         $dbman->create_table($table);
1095         $DB->insert_record($tablename, array('course' => 3));
1096         $DB->insert_record($tablename, array('course' => 3));
1097         $DB->insert_record($tablename, array('course' => 5));
1098         $DB->insert_record($tablename, array('course' => 2));
1100         $rs = $DB->get_recordset_list($tablename, 'course', array(3, 2));
1102         $counter = 0;
1103         foreach ($rs as $record) {
1104             $counter++;
1105         }
1106         $this->assertEqual(3, $counter);
1107         $rs->close();
1109         $rs = $DB->get_recordset_list($tablename, 'course',array()); /// Must return 0 rows without conditions. MDL-17645
1111         $counter = 0;
1112         foreach ($rs as $record) {
1113             $counter++;
1114         }
1115         $rs->close();
1116         $this->assertEqual(0, $counter);
1118         // notes:
1119         //  * limits are tested in test_get_recordset_sql()
1120         //  * where_clause() is used internally and is tested in test_get_records()
1121     }
1123     public function test_get_recordset_select() {
1124         $DB = $this->tdb;
1125         $dbman = $DB->get_manager();
1127         $table = $this->get_test_table();
1128         $tablename = $table->getName();
1130         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1131         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1132         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1133         $dbman->create_table($table);
1135         $DB->insert_record($tablename, array('course' => 3));
1136         $DB->insert_record($tablename, array('course' => 3));
1137         $DB->insert_record($tablename, array('course' => 5));
1138         $DB->insert_record($tablename, array('course' => 2));
1140         $rs = $DB->get_recordset_select($tablename, '');
1141         $counter = 0;
1142         foreach ($rs as $record) {
1143             $counter++;
1144         }
1145         $rs->close();
1146         $this->assertEqual(4, $counter);
1148         $this->assertTrue($rs = $DB->get_recordset_select($tablename, 'course = 3'));
1149         $counter = 0;
1150         foreach ($rs as $record) {
1151             $counter++;
1152         }
1153         $rs->close();
1154         $this->assertEqual(2, $counter);
1156         // notes:
1157         //  * limits are tested in test_get_recordset_sql()
1158     }
1160     public function test_get_recordset_sql() {
1161         $DB = $this->tdb;
1162         $dbman = $DB->get_manager();
1164         $table = $this->get_test_table();
1165         $tablename = $table->getName();
1167         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1168         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1169         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1170         $dbman->create_table($table);
1172         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
1173         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
1174         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
1175         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
1176         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
1177         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
1178         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
1180         $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
1181         $counter = 0;
1182         foreach ($rs as $record) {
1183             $counter++;
1184         }
1185         $rs->close();
1186         $this->assertEqual(2, $counter);
1188         // limits - only need to test this case, the rest have been tested by test_get_records_sql()
1189         // only limitfrom = skips that number of records
1190         $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
1191         $records = array();
1192         foreach($rs as $key => $record) {
1193             $records[$key] = $record;
1194         }
1195         $rs->close();
1196         $this->assertEqual(5, count($records));
1197         $this->assertEqual($inskey3, reset($records)->id);
1198         $this->assertEqual($inskey7, end($records)->id);
1200         // note: fetching nulls, empties, LOBs already tested by test_insert_record() no needed here
1201     }
1203     public function test_get_records() {
1204         $DB = $this->tdb;
1205         $dbman = $DB->get_manager();
1207         $table = $this->get_test_table();
1208         $tablename = $table->getName();
1210         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1211         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1212         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1213         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1214         $dbman->create_table($table);
1216         $DB->insert_record($tablename, array('course' => 3));
1217         $DB->insert_record($tablename, array('course' => 3));
1218         $DB->insert_record($tablename, array('course' => 5));
1219         $DB->insert_record($tablename, array('course' => 2));
1221         // All records
1222         $records = $DB->get_records($tablename);
1223         $this->assertEqual(4, count($records));
1224         $this->assertEqual(3, $records[1]->course);
1225         $this->assertEqual(3, $records[2]->course);
1226         $this->assertEqual(5, $records[3]->course);
1227         $this->assertEqual(2, $records[4]->course);
1229         // Records matching certain conditions
1230         $records = $DB->get_records($tablename, array('course' => 3));
1231         $this->assertEqual(2, count($records));
1232         $this->assertEqual(3, $records[1]->course);
1233         $this->assertEqual(3, $records[2]->course);
1235         // All records sorted by course
1236         $records = $DB->get_records($tablename, null, 'course');
1237         $this->assertEqual(4, count($records));
1238         $current_record = reset($records);
1239         $this->assertEqual(4, $current_record->id);
1240         $current_record = next($records);
1241         $this->assertEqual(1, $current_record->id);
1242         $current_record = next($records);
1243         $this->assertEqual(2, $current_record->id);
1244         $current_record = next($records);
1245         $this->assertEqual(3, $current_record->id);
1247         // All records, but get only one field
1248         $records = $DB->get_records($tablename, null, '', 'id');
1249         $this->assertFalse(isset($records[1]->course));
1250         $this->assertTrue(isset($records[1]->id));
1251         $this->assertEqual(4, count($records));
1253         // Booleans into params
1254         $records = $DB->get_records($tablename, array('course' => true));
1255         $this->assertEqual(0, count($records));
1256         $records = $DB->get_records($tablename, array('course' => false));
1257         $this->assertEqual(0, count($records));
1259         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
1260         $conditions = array('onetext' => '1');
1261         try {
1262             $records = $DB->get_records($tablename, $conditions);
1263             $this->fail('An Exception is missing, expected due to equating of text fields');
1264         } catch (exception $e) {
1265             $this->assertTrue($e instanceof dml_exception);
1266             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
1267         }
1269         // test get_records passing non-existing table
1270         try {
1271             $records = $DB->get_records('xxxx', array('id' => 0));
1272             $this->fail('An Exception is missing, expected due to query against non-existing table');
1273         } catch (exception $e) {
1274             $this->assertTrue($e instanceof dml_exception);
1275             $this->assertEqual($e->errorcode, 'ddltablenotexist');
1276         }
1278         // test get_records passing non-existing column
1279         try {
1280             $records = $DB->get_records($tablename, array('xxxx' => 0));
1281             $this->fail('An Exception is missing, expected due to query against non-existing column');
1282         } catch (exception $e) {
1283             $this->assertTrue($e instanceof dml_exception);
1284             $this->assertEqual($e->errorcode, 'ddlfieldnotexist');
1285         }
1287         // note: delegate limits testing to test_get_records_sql()
1288     }
1290     public function test_get_records_list() {
1291         $DB = $this->tdb;
1292         $dbman = $DB->get_manager();
1294         $table = $this->get_test_table();
1295         $tablename = $table->getName();
1297         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1298         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1299         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1300         $dbman->create_table($table);
1302         $DB->insert_record($tablename, array('course' => 3));
1303         $DB->insert_record($tablename, array('course' => 3));
1304         $DB->insert_record($tablename, array('course' => 5));
1305         $DB->insert_record($tablename, array('course' => 2));
1307         $records = $DB->get_records_list($tablename, 'course', array(3, 2));
1308         $this->assertTrue(is_array($records));
1309         $this->assertEqual(3, count($records));
1310         $this->assertEqual(1, reset($records)->id);
1311         $this->assertEqual(2, next($records)->id);
1312         $this->assertEqual(4, next($records)->id);
1314         $this->assertIdentical(array(), $records = $DB->get_records_list($tablename, 'course', array())); /// Must return 0 rows without conditions. MDL-17645
1315         $this->assertEqual(0, count($records));
1317         // note: delegate limits testing to test_get_records_sql()
1318     }
1320     public function test_get_records_sql() {
1321         $DB = $this->tdb;
1322         $dbman = $DB->get_manager();
1324         $table = $this->get_test_table();
1325         $tablename = $table->getName();
1327         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1328         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1329         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1330         $dbman->create_table($table);
1332         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
1333         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
1334         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
1335         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
1336         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
1337         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
1338         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
1340         $table2 = $this->get_test_table("2");
1341         $tablename2 = $table2->getName();
1342         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1343         $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1344         $table2->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
1345         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1346         $dbman->create_table($table2);
1348         $DB->insert_record($tablename2, array('course'=>3, 'nametext'=>'badabing'));
1349         $DB->insert_record($tablename2, array('course'=>4, 'nametext'=>'badabang'));
1350         $DB->insert_record($tablename2, array('course'=>5, 'nametext'=>'badabung'));
1351         $DB->insert_record($tablename2, array('course'=>6, 'nametext'=>'badabong'));
1353         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
1354         $this->assertEqual(2, count($records));
1355         $this->assertEqual($inskey1, reset($records)->id);
1356         $this->assertEqual($inskey4, next($records)->id);
1358         // Awful test, requires debug enabled and sent to browser. Let's do that and restore after test
1359         $this->enable_debugging();
1360         $records = $DB->get_records_sql("SELECT course AS id, course AS course FROM {{$tablename}}", null);
1361         $this->assertFalse($this->get_debugging() === '');
1362         $this->assertEqual(6, count($records));
1364         // negative limits = no limits
1365         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, -1, -1);
1366         $this->assertEqual(7, count($records));
1368         // zero limits = no limits
1369         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 0);
1370         $this->assertEqual(7, count($records));
1372         // only limitfrom = skips that number of records
1373         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
1374         $this->assertEqual(5, count($records));
1375         $this->assertEqual($inskey3, reset($records)->id);
1376         $this->assertEqual($inskey7, end($records)->id);
1378         // only limitnum = fetches that number of records
1379         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 3);
1380         $this->assertEqual(3, count($records));
1381         $this->assertEqual($inskey1, reset($records)->id);
1382         $this->assertEqual($inskey3, end($records)->id);
1384         // both limitfrom and limitnum = skips limitfrom records and fetches limitnum ones
1385         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 3, 2);
1386         $this->assertEqual(2, count($records));
1387         $this->assertEqual($inskey4, reset($records)->id);
1388         $this->assertEqual($inskey5, end($records)->id);
1390         // both limitfrom and limitnum in query having subqueris
1391         // note the subquery skips records with course = 0 and 3
1392         $sql = "SELECT * FROM {{$tablename}}
1393                  WHERE course NOT IN (
1394                      SELECT course FROM {{$tablename}}
1395                       WHERE course IN (0, 3))
1396                 ORDER BY course";
1397         $records = $DB->get_records_sql($sql, null, 0, 2); // Skip 0, get 2
1398         $this->assertEqual(2, count($records));
1399         $this->assertEqual($inskey6, reset($records)->id);
1400         $this->assertEqual($inskey5, end($records)->id);
1401         $records = $DB->get_records_sql($sql, null, 2, 2); // Skip 2, get 2
1402         $this->assertEqual(2, count($records));
1403         $this->assertEqual($inskey3, reset($records)->id);
1404         $this->assertEqual($inskey2, end($records)->id);
1406         // test 2 tables with aliases and limits with order bys
1407         $sql = "SELECT t1.id, t1.course AS cid, t2.nametext
1408                   FROM {{$tablename}} t1, {{$tablename2}} t2
1409                  WHERE t2.course=t1.course
1410               ORDER BY t1.course, ". $DB->sql_compare_text('t2.nametext');
1411         $records = $DB->get_records_sql($sql, null, 2, 2); // Skip courses 3 and 6, get 4 and 5
1412         $this->assertEqual(2, count($records));
1413         $this->assertEqual('5', end($records)->cid);
1414         $this->assertEqual('4', reset($records)->cid);
1416         // test 2 tables with aliases and limits with the highest INT limit works
1417         $records = $DB->get_records_sql($sql, null, 2, PHP_INT_MAX); // Skip course {3,6}, get {4,5}
1418         $this->assertEqual(2, count($records));
1419         $this->assertEqual('5', end($records)->cid);
1420         $this->assertEqual('4', reset($records)->cid);
1422         // test 2 tables with aliases and limits with order bys (limit which is highest INT number)
1423         $records = $DB->get_records_sql($sql, null, PHP_INT_MAX, 2); // Skip all courses
1424         $this->assertEqual(0, count($records));
1426         // test 2 tables with aliases and limits with order bys (limit which s highest INT number)
1427         $records = $DB->get_records_sql($sql, null, PHP_INT_MAX, PHP_INT_MAX); // Skip all courses
1428         $this->assertEqual(0, count($records));
1430         // TODO: Test limits in queries having DISTINCT clauses
1432         // note: fetching nulls, empties, LOBs already tested by test_update_record() no needed here
1433     }
1435     public function test_get_records_menu() {
1436         $DB = $this->tdb;
1437         $dbman = $DB->get_manager();
1439         $table = $this->get_test_table();
1440         $tablename = $table->getName();
1442         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1443         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1444         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1445         $dbman->create_table($table);
1447         $DB->insert_record($tablename, array('course' => 3));
1448         $DB->insert_record($tablename, array('course' => 3));
1449         $DB->insert_record($tablename, array('course' => 5));
1450         $DB->insert_record($tablename, array('course' => 2));
1452         $records = $DB->get_records_menu($tablename, array('course' => 3));
1453         $this->assertTrue(is_array($records));
1454         $this->assertEqual(2, count($records));
1455         $this->assertFalse(empty($records[1]));
1456         $this->assertFalse(empty($records[2]));
1457         $this->assertEqual(3, $records[1]);
1458         $this->assertEqual(3, $records[2]);
1460         // note: delegate limits testing to test_get_records_sql()
1461     }
1463     public function test_get_records_select_menu() {
1464         $DB = $this->tdb;
1465         $dbman = $DB->get_manager();
1467         $table = $this->get_test_table();
1468         $tablename = $table->getName();
1470         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1471         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1472         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1473         $dbman->create_table($table);
1475         $DB->insert_record($tablename, array('course' => 3));
1476         $DB->insert_record($tablename, array('course' => 2));
1477         $DB->insert_record($tablename, array('course' => 3));
1478         $DB->insert_record($tablename, array('course' => 5));
1480         $records = $DB->get_records_select_menu($tablename, "course > ?", array(2));
1481         $this->assertTrue(is_array($records));
1483         $this->assertEqual(3, count($records));
1484         $this->assertFalse(empty($records[1]));
1485         $this->assertTrue(empty($records[2]));
1486         $this->assertFalse(empty($records[3]));
1487         $this->assertFalse(empty($records[4]));
1488         $this->assertEqual(3, $records[1]);
1489         $this->assertEqual(3, $records[3]);
1490         $this->assertEqual(5, $records[4]);
1492         // note: delegate limits testing to test_get_records_sql()
1493     }
1495     public function test_get_records_sql_menu() {
1496         $DB = $this->tdb;
1497         $dbman = $DB->get_manager();
1499         $table = $this->get_test_table();
1500         $tablename = $table->getName();
1502         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1503         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1504         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1505         $dbman->create_table($table);
1507         $DB->insert_record($tablename, array('course' => 3));
1508         $DB->insert_record($tablename, array('course' => 2));
1509         $DB->insert_record($tablename, array('course' => 3));
1510         $DB->insert_record($tablename, array('course' => 5));
1512         $records = $DB->get_records_sql_menu("SELECT * FROM {{$tablename}} WHERE course > ?", array(2));
1513         $this->assertTrue(is_array($records));
1515         $this->assertEqual(3, count($records));
1516         $this->assertFalse(empty($records[1]));
1517         $this->assertTrue(empty($records[2]));
1518         $this->assertFalse(empty($records[3]));
1519         $this->assertFalse(empty($records[4]));
1520         $this->assertEqual(3, $records[1]);
1521         $this->assertEqual(3, $records[3]);
1522         $this->assertEqual(5, $records[4]);
1524         // note: delegate limits testing to test_get_records_sql()
1525     }
1527     public function test_get_record() {
1528         $DB = $this->tdb;
1529         $dbman = $DB->get_manager();
1531         $table = $this->get_test_table();
1532         $tablename = $table->getName();
1534         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1535         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1536         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1537         $dbman->create_table($table);
1539         $DB->insert_record($tablename, array('course' => 3));
1540         $DB->insert_record($tablename, array('course' => 2));
1542         $record = $DB->get_record($tablename, array('id' => 2));
1543         $this->assertTrue($record instanceof stdClass);
1545         $this->assertEqual(2, $record->course);
1546         $this->assertEqual(2, $record->id);
1547     }
1550     public function test_get_record_select() {
1551         $DB = $this->tdb;
1552         $dbman = $DB->get_manager();
1554         $table = $this->get_test_table();
1555         $tablename = $table->getName();
1557         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1558         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1559         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1560         $dbman->create_table($table);
1562         $DB->insert_record($tablename, array('course' => 3));
1563         $DB->insert_record($tablename, array('course' => 2));
1565         $record = $DB->get_record_select($tablename, "id = ?", array(2));
1566         $this->assertTrue($record instanceof stdClass);
1568         $this->assertEqual(2, $record->course);
1570         // note: delegates limit testing to test_get_records_sql()
1571     }
1573     public function test_get_record_sql() {
1574         $DB = $this->tdb;
1575         $dbman = $DB->get_manager();
1577         $table = $this->get_test_table();
1578         $tablename = $table->getName();
1580         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1581         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1582         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1583         $dbman->create_table($table);
1585         $DB->insert_record($tablename, array('course' => 3));
1586         $DB->insert_record($tablename, array('course' => 2));
1588         // standard use
1589         $record = $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(2));
1590         $this->assertTrue($record instanceof stdClass);
1591         $this->assertEqual(2, $record->course);
1592         $this->assertEqual(2, $record->id);
1594         // backwards compatibility with $ignoremultiple
1595         $this->assertFalse(IGNORE_MISSING);
1596         $this->assertTrue(IGNORE_MULTIPLE);
1598         // record not found - ignore
1599         $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MISSING));
1600         $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MULTIPLE));
1602         // record not found error
1603         try {
1604             $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), MUST_EXIST);
1605             $this->fail("Exception expected");
1606         } catch (dml_missing_record_exception $e) {
1607             $this->assertTrue(true);
1608         }
1610         $this->enable_debugging();
1611         $this->assertTrue($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MISSING));
1612         $this->assertFalse($this->get_debugging() === '');
1614         // multiple matches ignored
1615         $this->assertTrue($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MULTIPLE));
1617         // multiple found error
1618         try {
1619             $DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), MUST_EXIST);
1620             $this->fail("Exception expected");
1621         } catch (dml_multiple_records_exception $e) {
1622             $this->assertTrue(true);
1623         }
1624     }
1626     public function test_get_field() {
1627         $DB = $this->tdb;
1628         $dbman = $DB->get_manager();
1630         $table = $this->get_test_table();
1631         $tablename = $table->getName();
1633         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1634         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1635         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1636         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1637         $dbman->create_table($table);
1639         $id1 = $DB->insert_record($tablename, array('course' => 3));
1640         $DB->insert_record($tablename, array('course' => 5));
1641         $DB->insert_record($tablename, array('course' => 5));
1643         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id1)));
1644         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('course' => 3)));
1646         $this->assertIdentical(false, $DB->get_field($tablename, 'course', array('course' => 11), IGNORE_MISSING));
1647         try {
1648             $DB->get_field($tablename, 'course', array('course' => 4), MUST_EXIST);
1649             $this->assertFail('Exception expected due to missing record');
1650         } catch (dml_exception $ex) {
1651             $this->assertTrue(true);
1652         }
1654         $this->enable_debugging();
1655         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MULTIPLE));
1656         $this->assertIdentical($this->get_debugging(), '');
1658         $this->enable_debugging();
1659         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MISSING));
1660         $this->assertFalse($this->get_debugging() === '');
1662         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
1663         $conditions = array('onetext' => '1');
1664         try {
1665             $DB->get_field($tablename, 'course', $conditions);
1666             $this->fail('An Exception is missing, expected due to equating of text fields');
1667         } catch (exception $e) {
1668             $this->assertTrue($e instanceof dml_exception);
1669             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
1670         }
1671     }
1673     public function test_get_field_select() {
1674         $DB = $this->tdb;
1675         $dbman = $DB->get_manager();
1677         $table = $this->get_test_table();
1678         $tablename = $table->getName();
1680         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1681         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1682         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1683         $dbman->create_table($table);
1685         $DB->insert_record($tablename, array('course' => 3));
1687         $this->assertEqual(3, $DB->get_field_select($tablename, 'course', "id = ?", array(1)));
1688     }
1690     public function test_get_field_sql() {
1691         $DB = $this->tdb;
1692         $dbman = $DB->get_manager();
1694         $table = $this->get_test_table();
1695         $tablename = $table->getName();
1697         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1698         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1699         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1700         $dbman->create_table($table);
1702         $DB->insert_record($tablename, array('course' => 3));
1704         $this->assertEqual(3, $DB->get_field_sql("SELECT course FROM {{$tablename}} WHERE id = ?", array(1)));
1705     }
1707     public function test_get_fieldset_select() {
1708         $DB = $this->tdb;
1709         $dbman = $DB->get_manager();
1711         $table = $this->get_test_table();
1712         $tablename = $table->getName();
1714         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1715         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1716         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1717         $dbman->create_table($table);
1719         $DB->insert_record($tablename, array('course' => 1));
1720         $DB->insert_record($tablename, array('course' => 3));
1721         $DB->insert_record($tablename, array('course' => 2));
1722         $DB->insert_record($tablename, array('course' => 6));
1724         $fieldset = $DB->get_fieldset_select($tablename, 'course', "course > ?", array(1));
1725         $this->assertTrue(is_array($fieldset));
1727         $this->assertEqual(3, count($fieldset));
1728         $this->assertEqual(3, $fieldset[0]);
1729         $this->assertEqual(2, $fieldset[1]);
1730         $this->assertEqual(6, $fieldset[2]);
1731     }
1733     public function test_get_fieldset_sql() {
1734         $DB = $this->tdb;
1735         $dbman = $DB->get_manager();
1737         $table = $this->get_test_table();
1738         $tablename = $table->getName();
1740         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1741         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1742         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1743         $dbman->create_table($table);
1745         $DB->insert_record($tablename, array('course' => 1));
1746         $DB->insert_record($tablename, array('course' => 3));
1747         $DB->insert_record($tablename, array('course' => 2));
1748         $DB->insert_record($tablename, array('course' => 6));
1750         $fieldset = $DB->get_fieldset_sql("SELECT * FROM {{$tablename}} WHERE course > ?", array(1));
1751         $this->assertTrue(is_array($fieldset));
1753         $this->assertEqual(3, count($fieldset));
1754         $this->assertEqual(2, $fieldset[0]);
1755         $this->assertEqual(3, $fieldset[1]);
1756         $this->assertEqual(4, $fieldset[2]);
1757     }
1759     public function test_insert_record_raw() {
1760         $DB = $this->tdb;
1761         $dbman = $DB->get_manager();
1763         $table = $this->get_test_table();
1764         $tablename = $table->getName();
1766         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1767         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1768         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1769         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1770         $dbman->create_table($table);
1772         $record = (object)array('course' => 1, 'onechar' => 'xx');
1773         $before = clone($record);
1774         $result = $DB->insert_record_raw($tablename, $record);
1775         $this->assertIdentical(1, $result);
1776         $this->assertIdentical($record, $before);
1778         $record = $DB->get_record($tablename, array('course' => 1));
1779         $this->assertTrue($record instanceof stdClass);
1780         $this->assertIdentical('xx', $record->onechar);
1782         $result = $DB->insert_record_raw($tablename, array('course' => 2, 'onechar' => 'yy'), false);
1783         $this->assertIdentical(true, $result);
1785         // note: bulk not implemented yet
1786         $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'zz'), true, true);
1787         $record = $DB->get_record($tablename, array('course' => 3));
1788         $this->assertTrue($record instanceof stdClass);
1789         $this->assertIdentical('zz', $record->onechar);
1791         // custom sequence (id) - returnid is ignored
1792         $result = $DB->insert_record_raw($tablename, array('id' => 10, 'course' => 3, 'onechar' => 'bb'), true, false, true);
1793         $this->assertIdentical(true, $result);
1794         $record = $DB->get_record($tablename, array('id' => 10));
1795         $this->assertTrue($record instanceof stdClass);
1796         $this->assertIdentical('bb', $record->onechar);
1798         // custom sequence - missing id error
1799         try {
1800             $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'bb'), true, false, true);
1801             $this->assertFail('Exception expected due to missing record');
1802         } catch (coding_exception $ex) {
1803             $this->assertTrue(true);
1804         }
1806         // wrong column error
1807         try {
1808             $DB->insert_record_raw($tablename, array('xxxxx' => 3, 'onechar' => 'bb'));
1809             $this->assertFail('Exception expected due to invalid column');
1810         } catch (dml_exception $ex) {
1811             $this->assertTrue(true);
1812         }
1813     }
1815     public function test_insert_record() {
1816         // All the information in this test is fetched from DB by get_recordset() so we
1817         // have such method properly tested against nulls, empties and friends...
1819         $DB = $this->tdb;
1820         $dbman = $DB->get_manager();
1822         $table = $this->get_test_table();
1823         $tablename = $table->getName();
1825         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1826         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1827         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
1828         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1829         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1830         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1831         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1832         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1833         $dbman->create_table($table);
1835         $this->assertIdentical(1, $DB->insert_record($tablename, array('course' => 1), true));
1836         $record = $DB->get_record($tablename, array('course' => 1));
1837         $this->assertEqual(1, $record->id);
1838         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
1839         $this->assertEqual(200, $record->onenum);
1840         $this->assertIdentical('onestring', $record->onechar);
1841         $this->assertNull($record->onetext);
1842         $this->assertNull($record->onebinary);
1844         // without returning id, bulk not implemented
1845         $result = $this->assertIdentical(true, $DB->insert_record($tablename, array('course' => 99), false, true));
1846         $record = $DB->get_record($tablename, array('course' => 99));
1847         $this->assertEqual(2, $record->id);
1848         $this->assertEqual(99, $record->course);
1850         // Check nulls are set properly for all types
1851         $record = new stdClass();
1852         $record->oneint = null;
1853         $record->onenum = null;
1854         $record->onechar = null;
1855         $record->onetext = null;
1856         $record->onebinary = null;
1857         $recid = $DB->insert_record($tablename, $record);
1858         $record = $DB->get_record($tablename, array('id' => $recid));
1859         $this->assertEqual(0, $record->course);
1860         $this->assertNull($record->oneint);
1861         $this->assertNull($record->onenum);
1862         $this->assertNull($record->onechar);
1863         $this->assertNull($record->onetext);
1864         $this->assertNull($record->onebinary);
1866         // Check zeros are set properly for all types
1867         $record = new stdClass();
1868         $record->oneint = 0;
1869         $record->onenum = 0;
1870         $recid = $DB->insert_record($tablename, $record);
1871         $record = $DB->get_record($tablename, array('id' => $recid));
1872         $this->assertEqual(0, $record->oneint);
1873         $this->assertEqual(0, $record->onenum);
1875         // Check booleans are set properly for all types
1876         $record = new stdClass();
1877         $record->oneint = true; // trues
1878         $record->onenum = true;
1879         $record->onechar = true;
1880         $record->onetext = true;
1881         $recid = $DB->insert_record($tablename, $record);
1882         $record = $DB->get_record($tablename, array('id' => $recid));
1883         $this->assertEqual(1, $record->oneint);
1884         $this->assertEqual(1, $record->onenum);
1885         $this->assertEqual(1, $record->onechar);
1886         $this->assertEqual(1, $record->onetext);
1888         $record = new stdClass();
1889         $record->oneint = false; // falses
1890         $record->onenum = false;
1891         $record->onechar = false;
1892         $record->onetext = false;
1893         $recid = $DB->insert_record($tablename, $record);
1894         $record = $DB->get_record($tablename, array('id' => $recid));
1895         $this->assertEqual(0, $record->oneint);
1896         $this->assertEqual(0, $record->onenum);
1897         $this->assertEqual(0, $record->onechar);
1898         $this->assertEqual(0, $record->onetext);
1900         // Check string data causes exception in numeric types
1901         $record = new stdClass();
1902         $record->oneint = 'onestring';
1903         $record->onenum = 0;
1904         try {
1905             $DB->insert_record($tablename, $record);
1906             $this->fail("Expecting an exception, none occurred");
1907         } catch (exception $e) {
1908             $this->assertTrue($e instanceof dml_exception);
1909         }
1910         $record = new stdClass();
1911         $record->oneint = 0;
1912         $record->onenum = 'onestring';
1913         try {
1914            $DB->insert_record($tablename, $record);
1915            $this->fail("Expecting an exception, none occurred");
1916         } catch (exception $e) {
1917             $this->assertTrue($e instanceof dml_exception);
1918         }
1920         // Check empty string data is stored as 0 in numeric datatypes
1921         $record = new stdClass();
1922         $record->oneint = ''; // empty string
1923         $record->onenum = 0;
1924         $recid = $DB->insert_record($tablename, $record);
1925         $record = $DB->get_record($tablename, array('id' => $recid));
1926         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
1928         $record = new stdClass();
1929         $record->oneint = 0;
1930         $record->onenum = ''; // empty string
1931         $recid = $DB->insert_record($tablename, $record);
1932         $record = $DB->get_record($tablename, array('id' => $recid));
1933         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
1935         // Check empty strings are set properly in string types
1936         $record = new stdClass();
1937         $record->oneint = 0;
1938         $record->onenum = 0;
1939         $record->onechar = '';
1940         $record->onetext = '';
1941         $recid = $DB->insert_record($tablename, $record);
1942         $record = $DB->get_record($tablename, array('id' => $recid));
1943         $this->assertTrue($record->onechar === '');
1944         $this->assertTrue($record->onetext === '');
1946         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1947         $record = new stdClass();
1948         $record->oneint = ((210.10 + 39.92) - 150.02);
1949         $record->onenum = ((210.10 + 39.92) - 150.02);
1950         $recid = $DB->insert_record($tablename, $record);
1951         $record = $DB->get_record($tablename, array('id' => $recid));
1952         $this->assertEqual(100, $record->oneint);
1953         $this->assertEqual(100, $record->onenum);
1955         // Check various quotes/backslashes combinations in string types
1956         $teststrings = array(
1957             'backslashes and quotes alone (even): "" \'\' \\\\',
1958             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1959             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1960             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1961         foreach ($teststrings as $teststring) {
1962             $record = new stdClass();
1963             $record->onechar = $teststring;
1964             $record->onetext = $teststring;
1965             $recid = $DB->insert_record($tablename, $record);
1966             $record = $DB->get_record($tablename, array('id' => $recid));
1967             $this->assertEqual($teststring, $record->onechar);
1968             $this->assertEqual($teststring, $record->onetext);
1969         }
1971         // Check LOBs in text/binary columns
1972         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
1973         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
1974         $record = new stdClass();
1975         $record->onetext = $clob;
1976         $record->onebinary = $blob;
1977         $recid = $DB->insert_record($tablename, $record);
1978         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1979         $record = $rs->current();
1980         $rs->close();
1981         $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
1982         $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
1984         // And "small" LOBs too, just in case
1985         $newclob = substr($clob, 0, 500);
1986         $newblob = substr($blob, 0, 250);
1987         $record = new stdClass();
1988         $record->onetext = $newclob;
1989         $record->onebinary = $newblob;
1990         $recid = $DB->insert_record($tablename, $record);
1991         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1992         $record = $rs->current();
1993         $rs->close();
1994         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
1995         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
1996         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
1998         // And "diagnostic" LOBs too, just in case
1999         $newclob = '\'"\\;/ěščřžýáíé';
2000         $newblob = '\'"\\;/ěščřžýáíé';
2001         $record = new stdClass();
2002         $record->onetext = $newclob;
2003         $record->onebinary = $newblob;
2004         $recid = $DB->insert_record($tablename, $record);
2005         $rs = $DB->get_recordset($tablename, array('id' => $recid));
2006         $record = $rs->current();
2007         $rs->close();
2008         $this->assertIdentical($newclob, $record->onetext);
2009         $this->assertIdentical($newblob, $record->onebinary);
2010         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
2012         // test data is not modified
2013         $record = new stdClass();
2014         $record->id     = -1; // has to be ignored
2015         $record->course = 3;
2016         $record->lalala = 'lalal'; // unused
2017         $before = clone($record);
2018         $DB->insert_record($tablename, $record);
2019         $this->assertEqual($record, $before);
2021         // make sure the id is always increasing and never reuses the same id
2022         $id1 = $DB->insert_record($tablename, array('course' => 3));
2023         $id2 = $DB->insert_record($tablename, array('course' => 3));
2024         $this->assertTrue($id1 < $id2);
2025         $DB->delete_records($tablename, array('id'=>$id2));
2026         $id3 = $DB->insert_record($tablename, array('course' => 3));
2027         $this->assertTrue($id2 < $id3);
2028         $DB->delete_records($tablename, array());
2029         $id4 = $DB->insert_record($tablename, array('course' => 3));
2030         $this->assertTrue($id3 < $id4);
2032         // Test saving a float in a CHAR column, and reading it back.
2033         $id = $DB->insert_record($tablename, array('onechar' => 1.0));
2034         $this->assertEqual(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2035         $id = $DB->insert_record($tablename, array('onechar' => 1e20));
2036         $this->assertEqual(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2037         $id = $DB->insert_record($tablename, array('onechar' => 1e-4));
2038         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2039         $id = $DB->insert_record($tablename, array('onechar' => 1e-5));
2040         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2041         $id = $DB->insert_record($tablename, array('onechar' => 1e-300));
2042         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2043         $id = $DB->insert_record($tablename, array('onechar' => 1e300));
2044         $this->assertEqual(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2046         // Test saving a float in a TEXT column, and reading it back.
2047         $id = $DB->insert_record($tablename, array('onetext' => 1.0));
2048         $this->assertEqual(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2049         $id = $DB->insert_record($tablename, array('onetext' => 1e20));
2050         $this->assertEqual(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2051         $id = $DB->insert_record($tablename, array('onetext' => 1e-4));
2052         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2053         $id = $DB->insert_record($tablename, array('onetext' => 1e-5));
2054         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2055         $id = $DB->insert_record($tablename, array('onetext' => 1e-300));
2056         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2057         $id = $DB->insert_record($tablename, array('onetext' => 1e300));
2058         $this->assertEqual(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2059     }
2061     public function test_import_record() {
2062         // All the information in this test is fetched from DB by get_recordset() so we
2063         // have such method properly tested against nulls, empties and friends...
2065         $DB = $this->tdb;
2066         $dbman = $DB->get_manager();
2068         $table = $this->get_test_table();
2069         $tablename = $table->getName();
2071         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2072         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2073         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
2074         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
2075         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
2076         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2077         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2078         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2079         $dbman->create_table($table);
2081         $this->assertIdentical(1, $DB->insert_record($tablename, array('course' => 1), true));
2082         $record = $DB->get_record($tablename, array('course' => 1));
2083         $this->assertEqual(1, $record->id);
2084         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
2085         $this->assertEqual(200, $record->onenum);
2086         $this->assertIdentical('onestring', $record->onechar);
2087         $this->assertNull($record->onetext);
2088         $this->assertNull($record->onebinary);
2090         // ignore extra columns
2091         $record = (object)array('id'=>13, 'course'=>2, 'xxxx'=>788778);
2092         $before = clone($record);
2093         $this->assertIdentical(true, $DB->import_record($tablename, $record));
2094         $this->assertIdentical($record, $before);
2095         $records = $DB->get_records($tablename);
2096         $this->assertEqual(2, $records[13]->course);
2098         // Check nulls are set properly for all types
2099         $record = new stdClass();
2100         $record->id = 20;
2101         $record->oneint = null;
2102         $record->onenum = null;
2103         $record->onechar = null;
2104         $record->onetext = null;
2105         $record->onebinary = null;
2106         $this->assertTrue($DB->import_record($tablename, $record));
2107         $record = $DB->get_record($tablename, array('id' => 20));
2108         $this->assertEqual(0, $record->course);
2109         $this->assertNull($record->oneint);
2110         $this->assertNull($record->onenum);
2111         $this->assertNull($record->onechar);
2112         $this->assertNull($record->onetext);
2113         $this->assertNull($record->onebinary);
2115         // Check zeros are set properly for all types
2116         $record = new stdClass();
2117         $record->id = 23;
2118         $record->oneint = 0;
2119         $record->onenum = 0;
2120         $this->assertTrue($DB->import_record($tablename, $record));
2121         $record = $DB->get_record($tablename, array('id' => 23));
2122         $this->assertEqual(0, $record->oneint);
2123         $this->assertEqual(0, $record->onenum);
2125         // Check string data causes exception in numeric types
2126         $record = new stdClass();
2127         $record->id = 32;
2128         $record->oneint = 'onestring';
2129         $record->onenum = 0;
2130         try {
2131             $DB->import_record($tablename, $record);
2132             $this->fail("Expecting an exception, none occurred");
2133         } catch (exception $e) {
2134             $this->assertTrue($e instanceof dml_exception);
2135         }
2136         $record = new stdClass();
2137         $record->id = 35;
2138         $record->oneint = 0;
2139         $record->onenum = 'onestring';
2140         try {
2141            $DB->import_record($tablename, $record);
2142            $this->fail("Expecting an exception, none occurred");
2143         } catch (exception $e) {
2144             $this->assertTrue($e instanceof dml_exception);
2145         }
2147         // Check empty strings are set properly in string types
2148         $record = new stdClass();
2149         $record->id = 44;
2150         $record->oneint = 0;
2151         $record->onenum = 0;
2152         $record->onechar = '';
2153         $record->onetext = '';
2154         $this->assertTrue($DB->import_record($tablename, $record));
2155         $record = $DB->get_record($tablename, array('id' => 44));
2156         $this->assertTrue($record->onechar === '');
2157         $this->assertTrue($record->onetext === '');
2159         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
2160         $record = new stdClass();
2161         $record->id = 47;
2162         $record->oneint = ((210.10 + 39.92) - 150.02);
2163         $record->onenum = ((210.10 + 39.92) - 150.02);
2164         $this->assertTrue($DB->import_record($tablename, $record));
2165         $record = $DB->get_record($tablename, array('id' => 47));
2166         $this->assertEqual(100, $record->oneint);
2167         $this->assertEqual(100, $record->onenum);
2169         // Check various quotes/backslashes combinations in string types
2170         $i = 50;
2171         $teststrings = array(
2172             'backslashes and quotes alone (even): "" \'\' \\\\',
2173             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2174             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2175             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2176         foreach ($teststrings as $teststring) {
2177             $record = new stdClass();
2178             $record->id = $i;
2179             $record->onechar = $teststring;
2180             $record->onetext = $teststring;
2181             $this->assertTrue($DB->import_record($tablename, $record));
2182             $record = $DB->get_record($tablename, array('id' => $i));
2183             $this->assertEqual($teststring, $record->onechar);
2184             $this->assertEqual($teststring, $record->onetext);
2185             $i = $i + 3;
2186         }
2188         // Check LOBs in text/binary columns
2189         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
2190         $record = new stdClass();
2191         $record->id = 70;
2192         $record->onetext = $clob;
2193         $record->onebinary = '';
2194         $this->assertTrue($DB->import_record($tablename, $record));
2195         $rs = $DB->get_recordset($tablename, array('id' => 70));
2196         $record = $rs->current();
2197         $rs->close();
2198         $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
2200         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
2201         $record = new stdClass();
2202         $record->id = 71;
2203         $record->onetext = '';
2204         $record->onebinary = $blob;
2205         $this->assertTrue($DB->import_record($tablename, $record));
2206         $rs = $DB->get_recordset($tablename, array('id' => 71));
2207         $record = $rs->current();
2208         $rs->close();
2209         $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
2211         // And "small" LOBs too, just in case
2212         $newclob = substr($clob, 0, 500);
2213         $newblob = substr($blob, 0, 250);
2214         $record = new stdClass();
2215         $record->id = 73;
2216         $record->onetext = $newclob;
2217         $record->onebinary = $newblob;
2218         $this->assertTrue($DB->import_record($tablename, $record));
2219         $rs = $DB->get_recordset($tablename, array('id' => 73));
2220         $record = $rs->current();
2221         $rs->close();
2222         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
2223         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
2224         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
2225     }
2227     public function test_update_record_raw() {
2228         $DB = $this->tdb;
2229         $dbman = $DB->get_manager();
2231         $table = $this->get_test_table();
2232         $tablename = $table->getName();
2234         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2235         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2236         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2237         $dbman->create_table($table);
2239         $DB->insert_record($tablename, array('course' => 1));
2240         $DB->insert_record($tablename, array('course' => 3));
2242         $record = $DB->get_record($tablename, array('course' => 1));
2243         $record->course = 2;
2244         $this->assertTrue($DB->update_record_raw($tablename, $record));
2245         $this->assertEqual(0, $DB->count_records($tablename, array('course' => 1)));
2246         $this->assertEqual(1, $DB->count_records($tablename, array('course' => 2)));
2247         $this->assertEqual(1, $DB->count_records($tablename, array('course' => 3)));
2249         $record = $DB->get_record($tablename, array('course' => 1));
2250         $record->xxxxx = 2;
2251         try {
2252            $DB->update_record_raw($tablename, $record);
2253            $this->fail("Expecting an exception, none occurred");
2254         } catch (Exception $e) {
2255             $this->assertTrue($e instanceof coding_exception);
2256         }
2258         $record = $DB->get_record($tablename, array('course' => 3));
2259         unset($record->id);
2260         try {
2261            $DB->update_record_raw($tablename, $record);
2262            $this->fail("Expecting an exception, none occurred");
2263         } catch (Exception $e) {
2264             $this->assertTrue($e instanceof coding_exception);
2265         }
2266     }
2268     public function test_update_record() {
2270         // All the information in this test is fetched from DB by get_record() so we
2271         // have such method properly tested against nulls, empties and friends...
2273         $DB = $this->tdb;
2274         $dbman = $DB->get_manager();
2276         $table = $this->get_test_table();
2277         $tablename = $table->getName();
2279         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2280         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2281         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
2282         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
2283         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
2284         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2285         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2286         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2287         $dbman->create_table($table);
2289         $DB->insert_record($tablename, array('course' => 1));
2290         $record = $DB->get_record($tablename, array('course' => 1));
2291         $record->course = 2;
2293         $this->assertTrue($DB->update_record($tablename, $record));
2294         $this->assertFalse($record = $DB->get_record($tablename, array('course' => 1)));
2295         $this->assertTrue($record = $DB->get_record($tablename, array('course' => 2)));
2296         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
2297         $this->assertEqual(200, $record->onenum);
2298         $this->assertEqual('onestring', $record->onechar);
2299         $this->assertNull($record->onetext);
2300         $this->assertNull($record->onebinary);
2302         // Check nulls are set properly for all types
2303         $record->oneint = null;
2304         $record->onenum = null;
2305         $record->onechar = null;
2306         $record->onetext = null;
2307         $record->onebinary = null;
2308         $DB->update_record($tablename, $record);
2309         $record = $DB->get_record($tablename, array('course' => 2));
2310         $this->assertNull($record->oneint);
2311         $this->assertNull($record->onenum);
2312         $this->assertNull($record->onechar);
2313         $this->assertNull($record->onetext);
2314         $this->assertNull($record->onebinary);
2316         // Check zeros are set properly for all types
2317         $record->oneint = 0;
2318         $record->onenum = 0;
2319         $DB->update_record($tablename, $record);
2320         $record = $DB->get_record($tablename, array('course' => 2));
2321         $this->assertEqual(0, $record->oneint);
2322         $this->assertEqual(0, $record->onenum);
2324         // Check booleans are set properly for all types
2325         $record->oneint = true; // trues
2326         $record->onenum = true;
2327         $record->onechar = true;
2328         $record->onetext = true;
2329         $DB->update_record($tablename, $record);
2330         $record = $DB->get_record($tablename, array('course' => 2));
2331         $this->assertEqual(1, $record->oneint);
2332         $this->assertEqual(1, $record->onenum);
2333         $this->assertEqual(1, $record->onechar);
2334         $this->assertEqual(1, $record->onetext);
2336         $record->oneint = false; // falses
2337         $record->onenum = false;
2338         $record->onechar = false;
2339         $record->onetext = false;
2340         $DB->update_record($tablename, $record);
2341         $record = $DB->get_record($tablename, array('course' => 2));
2342         $this->assertEqual(0, $record->oneint);
2343         $this->assertEqual(0, $record->onenum);
2344         $this->assertEqual(0, $record->onechar);
2345         $this->assertEqual(0, $record->onetext);
2347         // Check string data causes exception in numeric types
2348         $record->oneint = 'onestring';
2349         $record->onenum = 0;
2350         try {
2351             $DB->update_record($tablename, $record);
2352             $this->fail("Expecting an exception, none occurred");
2353         } catch (exception $e) {
2354             $this->assertTrue($e instanceof dml_exception);
2355         }
2356         $record->oneint = 0;
2357         $record->onenum = 'onestring';
2358         try {
2359             $DB->update_record($tablename, $record);
2360             $this->fail("Expecting an exception, none occurred");
2361         } catch (exception $e) {
2362             $this->assertTrue($e instanceof dml_exception);
2363         }
2365         // Check empty string data is stored as 0 in numeric datatypes
2366         $record->oneint = ''; // empty string
2367         $record->onenum = 0;
2368         $DB->update_record($tablename, $record);
2369         $record = $DB->get_record($tablename, array('course' => 2));
2370         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
2372         $record->oneint = 0;
2373         $record->onenum = ''; // empty string
2374         $DB->update_record($tablename, $record);
2375         $record = $DB->get_record($tablename, array('course' => 2));
2376         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
2378         // Check empty strings are set properly in string types
2379         $record->oneint = 0;
2380         $record->onenum = 0;
2381         $record->onechar = '';
2382         $record->onetext = '';
2383         $DB->update_record($tablename, $record);
2384         $record = $DB->get_record($tablename, array('course' => 2));
2385         $this->assertTrue($record->onechar === '');
2386         $this->assertTrue($record->onetext === '');
2388         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
2389         $record->oneint = ((210.10 + 39.92) - 150.02);
2390         $record->onenum = ((210.10 + 39.92) - 150.02);
2391         $DB->update_record($tablename, $record);
2392         $record = $DB->get_record($tablename, array('course' => 2));
2393         $this->assertEqual(100, $record->oneint);
2394         $this->assertEqual(100, $record->onenum);
2396         // Check various quotes/backslashes combinations in string types
2397         $teststrings = array(
2398             'backslashes and quotes alone (even): "" \'\' \\\\',
2399             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2400             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2401             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2402         foreach ($teststrings as $teststring) {
2403             $record->onechar = $teststring;
2404             $record->onetext = $teststring;
2405             $DB->update_record($tablename, $record);
2406             $record = $DB->get_record($tablename, array('course' => 2));
2407             $this->assertEqual($teststring, $record->onechar);
2408             $this->assertEqual($teststring, $record->onetext);
2409         }
2411         // Check LOBs in text/binary columns
2412         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
2413         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
2414         $record->onetext = $clob;
2415         $record->onebinary = $blob;
2416         $DB->update_record($tablename, $record);
2417         $record = $DB->get_record($tablename, array('course' => 2));
2418         $this->assertEqual($clob, $record->onetext, 'Test CLOB update (full contents output disabled)');
2419         $this->assertEqual($blob, $record->onebinary, 'Test BLOB update (full contents output disabled)');
2421         // And "small" LOBs too, just in case
2422         $newclob = substr($clob, 0, 500);
2423         $newblob = substr($blob, 0, 250);
2424         $record->onetext = $newclob;
2425         $record->onebinary = $newblob;
2426         $DB->update_record($tablename, $record);
2427         $record = $DB->get_record($tablename, array('course' => 2));
2428         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB update (full contents output disabled)');
2429         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB update (full contents output disabled)');
2431         // Test saving a float in a CHAR column, and reading it back.
2432         $id = $DB->insert_record($tablename, array('onechar' => 'X'));
2433         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1.0));
2434         $this->assertEqual(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2435         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e20));
2436         $this->assertEqual(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2437         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-4));
2438         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2439         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-5));
2440         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2441         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-300));
2442         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2443         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e300));
2444         $this->assertEqual(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2446         // Test saving a float in a TEXT column, and reading it back.
2447         $id = $DB->insert_record($tablename, array('onetext' => 'X'));
2448         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1.0));
2449         $this->assertEqual(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2450         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e20));
2451         $this->assertEqual(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2452         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-4));
2453         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2454         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-5));
2455         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2456         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-300));
2457         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2458         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e300));
2459         $this->assertEqual(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2460     }
2462     public function test_set_field() {
2463         $DB = $this->tdb;
2464         $dbman = $DB->get_manager();
2466         $table = $this->get_test_table();
2467         $tablename = $table->getName();
2469         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2470         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2471         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
2472         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2473         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2474         $dbman->create_table($table);
2476         // simple set_field
2477         $id1 = $DB->insert_record($tablename, array('course' => 1));
2478         $id2 = $DB->insert_record($tablename, array('course' => 1));
2479         $id3 = $DB->insert_record($tablename, array('course' => 3));
2480         $this->assertTrue($DB->set_field($tablename, 'course', 2, array('id' => $id1)));
2481         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => $id1)));
2482         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
2483         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2484         $DB->delete_records($tablename, array());
2486         // multiple fields affected
2487         $id1 = $DB->insert_record($tablename, array('course' => 1));
2488         $id2 = $DB->insert_record($tablename, array('course' => 1));
2489         $id3 = $DB->insert_record($tablename, array('course' => 3));
2490         $DB->set_field($tablename, 'course', '5', array('course' => 1));
2491         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
2492         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
2493         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2494         $DB->delete_records($tablename, array());
2496         // no field affected
2497         $id1 = $DB->insert_record($tablename, array('course' => 1));
2498         $id2 = $DB->insert_record($tablename, array('course' => 1));
2499         $id3 = $DB->insert_record($tablename, array('course' => 3));
2500         $DB->set_field($tablename, 'course', '5', array('course' => 0));
2501         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id1)));
2502         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
2503         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2504         $DB->delete_records($tablename, array());
2506         // all fields - no condition
2507         $id1 = $DB->insert_record($tablename, array('course' => 1));
2508         $id2 = $DB->insert_record($tablename, array('course' => 1));
2509         $id3 = $DB->insert_record($tablename, array('course' => 3));
2510         $DB->set_field($tablename, 'course', 5, array());
2511         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
2512         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
2513         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id3)));
2515         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2516         $conditions = array('onetext' => '1');
2517         try {
2518             $DB->set_field($tablename, 'onechar', 'frog', $conditions);
2519             $this->fail('An Exception is missing, expected due to equating of text fields');
2520         } catch (exception $e) {
2521             $this->assertTrue($e instanceof dml_exception);
2522             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2523         }
2525         // Test saving a float in a CHAR column, and reading it back.
2526         $id = $DB->insert_record($tablename, array('onechar' => 'X'));
2527         $DB->set_field($tablename, 'onechar', 1.0, array('id' => $id));
2528         $this->assertEqual(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2529         $DB->set_field($tablename, 'onechar', 1e20, array('id' => $id));
2530         $this->assertEqual(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2531         $DB->set_field($tablename, 'onechar', 1e-4, array('id' => $id));
2532         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2533         $DB->set_field($tablename, 'onechar', 1e-5, array('id' => $id));
2534         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2535         $DB->set_field($tablename, 'onechar', 1e-300, array('id' => $id));
2536         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2537         $DB->set_field($tablename, 'onechar', 1e300, array('id' => $id));
2538         $this->assertEqual(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2540         // Test saving a float in a TEXT column, and reading it back.
2541         $id = $DB->insert_record($tablename, array('onetext' => 'X'));
2542         $DB->set_field($tablename, 'onetext', 1.0, array('id' => $id));
2543         $this->assertEqual(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2544         $DB->set_field($tablename, 'onetext', 1e20, array('id' => $id));
2545         $this->assertEqual(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2546         $DB->set_field($tablename, 'onetext', 1e-4, array('id' => $id));
2547         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2548         $DB->set_field($tablename, 'onetext', 1e-5, array('id' => $id));
2549         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2550         $DB->set_field($tablename, 'onetext', 1e-300, array('id' => $id));
2551         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2552         $DB->set_field($tablename, 'onetext', 1e300, array('id' => $id));
2553         $this->assertEqual(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2555         // Note: All the nulls, booleans, empties, quoted and backslashes tests
2556         // go to set_field_select() because set_field() is just one wrapper over it
2557     }
2559     public function test_set_field_select() {
2561         // All the information in this test is fetched from DB by get_field() so we
2562         // have such method properly tested against nulls, empties and friends...
2564         $DB = $this->tdb;
2565         $dbman = $DB->get_manager();
2567         $table = $this->get_test_table();
2568         $tablename = $table->getName();
2570         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2571         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2572         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null);
2573         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null);
2574         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
2575         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2576         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2577         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2578         $dbman->create_table($table);
2580         $DB->insert_record($tablename, array('course' => 1));
2582         $this->assertTrue($DB->set_field_select($tablename, 'course', 2, 'id = ?', array(1)));
2583         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => 1)));
2585         // Check nulls are set properly for all types
2586         $DB->set_field_select($tablename, 'oneint', null, 'id = ?', array(1)); // trues
2587         $DB->set_field_select($tablename, 'onenum', null, 'id = ?', array(1));
2588         $DB->set_field_select($tablename, 'onechar', null, 'id = ?', array(1));
2589         $DB->set_field_select($tablename, 'onetext', null, 'id = ?', array(1));
2590         $DB->set_field_select($tablename, 'onebinary', null, 'id = ?', array(1));
2591         $this->assertNull($DB->get_field($tablename, 'oneint', array('id' => 1)));
2592         $this->assertNull($DB->get_field($tablename, 'onenum', array('id' => 1)));
2593         $this->assertNull($DB->get_field($tablename, 'onechar', array('id' => 1)));
2594         $this->assertNull($DB->get_field($tablename, 'onetext', array('id' => 1)));
2595         $this->assertNull($DB->get_field($tablename, 'onebinary', array('id' => 1)));
2597         // Check zeros are set properly for all types
2598         $DB->set_field_select($tablename, 'oneint', 0, 'id = ?', array(1));
2599         $DB->set_field_select($tablename, 'onenum', 0, 'id = ?', array(1));
2600         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2601         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2603         // Check booleans are set properly for all types
2604         $DB->set_field_select($tablename, 'oneint', true, 'id = ?', array(1)); // trues
2605         $DB->set_field_select($tablename, 'onenum', true, 'id = ?', array(1));
2606         $DB->set_field_select($tablename, 'onechar', true, 'id = ?', array(1));
2607         $DB->set_field_select($tablename, 'onetext', true, 'id = ?', array(1));
2608         $this->assertEqual(1, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2609         $this->assertEqual(1, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2610         $this->assertEqual(1, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2611         $this->assertEqual(1, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2613         $DB->set_field_select($tablename, 'oneint', false, 'id = ?', array(1)); // falses
2614         $DB->set_field_select($tablename, 'onenum', false, 'id = ?', array(1));
2615         $DB->set_field_select($tablename, 'onechar', false, 'id = ?', array(1));
2616         $DB->set_field_select($tablename, 'onetext', false, 'id = ?', array(1));
2617         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2618         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2619         $this->assertEqual(0, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2620         $this->assertEqual(0, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2622         // Check string data causes exception in numeric types
2623         try {
2624             $DB->set_field_select($tablename, 'oneint', 'onestring', 'id = ?', array(1));
2625             $this->fail("Expecting an exception, none occurred");
2626         } catch (exception $e) {
2627             $this->assertTrue($e instanceof dml_exception);
2628         }
2629         try {
2630             $DB->set_field_select($tablename, 'onenum', 'onestring', 'id = ?', array(1));
2631             $this->fail("Expecting an exception, none occurred");
2632         } catch (exception $e) {
2633             $this->assertTrue($e instanceof dml_exception);
2634         }
2636         // Check empty string data is stored as 0 in numeric datatypes
2637         $DB->set_field_select($tablename, 'oneint', '', 'id = ?', array(1));
2638         $field = $DB->get_field($tablename, 'oneint', array('id' => 1));
2639         $this->assertTrue(is_numeric($field) && $field == 0);
2641         $DB->set_field_select($tablename, 'onenum', '', 'id = ?', array(1));
2642         $field = $DB->get_field($tablename, 'onenum', array('id' => 1));
2643         $this->assertTrue(is_numeric($field) && $field == 0);
2645         // Check empty strings are set properly in string types
2646         $DB->set_field_select($tablename, 'onechar', '', 'id = ?', array(1));
2647         $DB->set_field_select($tablename, 'onetext', '', 'id = ?', array(1));
2648         $this->assertTrue($DB->get_field($tablename, 'onechar', array('id' => 1)) === '');
2649         $this->assertTrue($DB->get_field($tablename, 'onetext', array('id' => 1)) === '');
2651         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
2652         $DB->set_field_select($tablename, 'oneint', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
2653         $DB->set_field_select($tablename, 'onenum', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
2654         $this->assertEqual(100, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2655         $this->assertEqual(100, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2657         // Check various quotes/backslashes combinations in string types
2658         $teststrings = array(
2659             'backslashes and quotes alone (even): "" \'\' \\\\',
2660             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2661             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2662             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2663         foreach ($teststrings as $teststring) {
2664             $DB->set_field_select($tablename, 'onechar', $teststring, 'id = ?', array(1));
2665             $DB->set_field_select($tablename, 'onetext', $teststring, 'id = ?', array(1));
2666             $this->assertEqual($teststring, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2667             $this->assertEqual($teststring, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2668         }
2670         // Check LOBs in text/binary columns
2671         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
2672         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
2673         $DB->set_field_select($tablename, 'onetext', $clob, 'id = ?', array(1));
2674         $DB->set_field_select($tablename, 'onebinary', $blob, 'id = ?', array(1));
2675         $this->assertEqual($clob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test CLOB set_field (full contents output disabled)');
2676         $this->assertEqual($blob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test BLOB set_field (full contents output disabled)');
2678         // And "small" LOBs too, just in case
2679         $newclob = substr($clob, 0, 500);
2680         $newblob = substr($blob, 0, 250);
2681         $DB->set_field_select($tablename, 'onetext', $newclob, 'id = ?', array(1));
2682         $DB->set_field_select($tablename, 'onebinary', $newblob, 'id = ?', array(1));
2683         $this->assertEqual($newclob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test "small" CLOB set_field (full contents output disabled)');
2684         $this->assertEqual($newblob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test "small" BLOB set_field (full contents output disabled)');
2686         // This is the failure from MDL-24863. This was giving an error on MSSQL,
2687         // which converts the '1' to an integer, which cannot then be compared with
2688         // onetext cast to a varchar. This should be fixed and working now.
2689         $newchar = 'frog';
2690         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2691         $params = array('onetext' => '1');
2692         try {
2693             $DB->set_field_select($tablename, 'onechar', $newchar, $DB->sql_compare_text('onetext') . ' = ?', $params);
2694             $this->assertTrue(true, 'No exceptions thrown with numerical text param comparison for text field.');
2695         } catch (dml_exception $e) {
2696             $this->assertFalse(true, 'We have an unexpected exception.');
2697             throw $e;
2698         }
2701     }
2703     public function test_count_records() {
2704         $DB = $this->tdb;
2706         $dbman = $DB->get_manager();
2708         $table = $this->get_test_table();
2709         $tablename = $table->getName();
2711         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2712         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2713         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2714         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2715         $dbman->create_table($table);
2717         $this->assertEqual(0, $DB->count_records($tablename));
2719         $DB->insert_record($tablename, array('course' => 3));
2720         $DB->insert_record($tablename, array('course' => 4));
2721         $DB->insert_record($tablename, array('course' => 5));
2723         $this->assertEqual(3, $DB->count_records($tablename));
2725         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2726         $conditions = array('onetext' => '1');
2727         try {
2728             $DB->count_records($tablename, $conditions);
2729             $this->fail('An Exception is missing, expected due to equating of text fields');
2730         } catch (exception $e) {
2731             $this->assertTrue($e instanceof dml_exception);
2732             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2733         }
2734     }
2736     public function test_count_records_select() {
2737         $DB = $this->tdb;
2739         $dbman = $DB->get_manager();
2741         $table = $this->get_test_table();
2742         $tablename = $table->getName();
2744         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2745         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2746         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2747         $dbman->create_table($table);
2749         $this->assertEqual(0, $DB->count_records($tablename));
2751         $DB->insert_record($tablename, array('course' => 3));
2752         $DB->insert_record($tablename, array('course' => 4));
2753         $DB->insert_record($tablename, array('course' => 5));
2755         $this->assertEqual(2, $DB->count_records_select($tablename, 'course > ?', array(3)));
2756     }
2758     public function test_count_records_sql() {
2759         $DB = $this->tdb;
2760         $dbman = $DB->get_manager();
2762         $table = $this->get_test_table();
2763         $tablename = $table->getName();
2765         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2766         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2767         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2768         $dbman->create_table($table);
2770         $this->assertEqual(0, $DB->count_records($tablename));
2772         $DB->insert_record($tablename, array('course' => 3));
2773         $DB->insert_record($tablename, array('course' => 4));
2774         $DB->insert_record($tablename, array('course' => 5));
2776         $this->assertEqual(2, $DB->count_records_sql("SELECT COUNT(*) FROM {{$tablename}} WHERE course > ?", array(3)));
2777     }
2779     public function test_record_exists() {
2780         $DB = $this->tdb;
2781         $dbman = $DB->get_manager();
2783         $table = $this->get_test_table();
2784         $tablename = $table->getName();
2786         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2787         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2788         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2789         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2790         $dbman->create_table($table);
2792         $this->assertEqual(0, $DB->count_records($tablename));
2794         $this->assertFalse($DB->record_exists($tablename, array('course' => 3)));
2795         $DB->insert_record($tablename, array('course' => 3));
2797         $this->assertTrue($DB->record_exists($tablename, array('course' => 3)));
2800         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2801         $conditions = array('onetext' => '1');
2802         try {
2803             $DB->record_exists($tablename, $conditions);
2804             $this->fail('An Exception is missing, expected due to equating of text fields');
2805         } catch (exception $e) {
2806             $this->assertTrue($e instanceof dml_exception);
2807             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2808         }
2809     }
2811     public function test_record_exists_select() {
2812         $DB = $this->tdb;
2813         $dbman = $DB->get_manager();
2815         $table = $this->get_test_table();
2816         $tablename = $table->getName();
2818         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2819         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2820         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2821         $dbman->create_table($table);
2823         $this->assertEqual(0, $DB->count_records($tablename));
2825         $this->assertFalse($DB->record_exists_select($tablename, "course = ?", array(3)));
2826         $DB->insert_record($tablename, array('course' => 3));
2828         $this->assertTrue($DB->record_exists_select($tablename, "course = ?", array(3)));
2829     }
2831     public function test_record_exists_sql() {
2832         $DB = $this->tdb;
2833         $dbman = $DB->get_manager();
2835         $table = $this->get_test_table();
2836         $tablename = $table->getName();
2838         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2839         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2840         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2841         $dbman->create_table($table);
2843         $this->assertEqual(0, $DB->count_records($tablename));
2845         $this->assertFalse($DB->record_exists_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3)));
2846         $DB->insert_record($tablename, array('course' => 3));
2848         $this->assertTrue($DB->record_exists_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3)));
2849     }
2851     public function test_recordset_locks_delete() {
2852         $DB = $this->tdb;
2853         $dbman = $DB->get_manager();
2855         //Setup
2856         $table = $this->get_test_table();
2857         $tablename = $table->getName();
2859         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2860         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2861         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2862         $dbman->create_table($table);
2864         $DB->insert_record($tablename, array('course' => 1));
2865         $DB->insert_record($tablename, array('course' => 2));
2866         $DB->insert_record($tablename, array('course' => 3));
2867         $DB->insert_record($tablename, array('course' => 4));
2868         $DB->insert_record($tablename, array('course' => 5));
2869         $DB->insert_record($tablename, array('course' => 6));
2871         // Test against db write locking while on an open recordset
2872         $rs = $DB->get_recordset($tablename, array(), null, 'course', 2, 2); // get courses = {3,4}
2873         foreach ($rs as $record) {
2874             $cid = $record->course;
2875             $DB->delete_records($tablename, array('course' => $cid));
2876             $this->assertFalse($DB->record_exists($tablename, array('course' => $cid)));
2877         }
2878         $rs->close();
2880         $this->assertEqual(4, $DB->count_records($tablename, array()));
2881     }
2883     public function test_recordset_locks_update() {
2884         $DB = $this->tdb;
2885         $dbman = $DB->get_manager();
2887         //Setup
2888         $table = $this->get_test_table();
2889         $tablename = $table->getName();
2891         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2892         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2893         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2894         $dbman->create_table($table);
2896         $DB->insert_record($tablename, array('course' => 1));
2897         $DB->insert_record($tablename, array('course' => 2));
2898         $DB->insert_record($tablename, array('course' => 3));
2899         $DB->insert_record($tablename, array('course' => 4));
2900         $DB->insert_record($tablename, array('course' => 5));
2901         $DB->insert_record($tablename, array('course' => 6));
2903         // Test against db write locking while on an open recordset
2904         $rs = $DB->get_recordset($tablename, array(), null, 'course', 2, 2); // get courses = {3,4}
2905         foreach ($rs as $record) {
2906             $cid = $record->course;
2907             $DB->set_field($tablename, 'course', 10, array('course' => $cid));
2908             $this->assertFalse($DB->record_exists($tablename, array('course' => $cid)));
2909         }
2910         $rs->close();
2912         $this->assertEqual(2, $DB->count_records($tablename, array('course' => 10)));
2913     }
2915     public function test_delete_records() {
2916         $DB = $this->tdb;
2917         $dbman = $DB->get_manager();
2919         $table = $this->get_test_table();
2920         $tablename = $table->getName();
2922         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2923         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2924         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2925         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2926         $dbman->create_table($table);
2928         $DB->insert_record($tablename, array('course' => 3));
2929         $DB->insert_record($tablename, array('course' => 2));
2930         $DB->insert_record($tablename, array('course' => 2));
2932         // Delete all records
2933         $this->assertTrue($DB->delete_records($tablename));
2934         $this->assertEqual(0, $DB->count_records($tablename));
2936         // Delete subset of records
2937         $DB->insert_record($tablename, array('course' => 3));
2938         $DB->insert_record($tablename, array('course' => 2));
2939         $DB->insert_record($tablename, array('course' => 2));
2941         $this->assertTrue($DB->delete_records($tablename, array('course' => 2)));
2942         $this->assertEqual(1, $DB->count_records($tablename));
2944         // delete all
2945         $this->assertTrue($DB->delete_records($tablename, array()));
2946         $this->assertEqual(0, $DB->count_records($tablename));
2948         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2949         $conditions = array('onetext'=>'1');
2950         try {
2951             $DB->delete_records($tablename, $conditions);
2952             $this->fail('An Exception is missing, expected due to equating of text fields');
2953         } catch (exception $e) {
2954             $this->assertTrue($e instanceof dml_exception);
2955             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2956         }
2958         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2959         $conditions = array('onetext' => 1);
2960         try {
2961             $DB->delete_records($tablename, $conditions);
2962             $this->fail('An Exception is missing, expected due to equating of text fields');
2963         } catch (exception $e) {
2964             $this->assertTrue($e instanceof dml_exception);
2965             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2966         }
2967     }
2969     public function test_delete_records_select() {
2970         $DB = $this->tdb;
2971         $dbman = $DB->get_manager();
2973         $table = $this->get_test_table();
2974         $tablename = $table->getName();
2976         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2977         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2978         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2979         $dbman->create_table($table);
2981         $DB->insert_record($tablename, array('course' => 3));
2982         $DB->insert_record($tablename, array('course' => 2));
2983         $DB->insert_record($tablename, array('course' => 2));
2985         $this->assertTrue($DB->delete_records_select($tablename, 'course = ?', array(2)));
2986         $this->assertEqual(1, $DB->count_records($tablename));
2987     }
2989     public function test_delete_records_list() {
2990         $DB = $this->tdb;
2991         $dbman = $DB->get_manager();
2993         $table = $this->get_test_table();
2994         $tablename = $table->getName();
2996         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2997         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2998         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2999         $dbman->create_table($table);
3001         $DB->insert_record($tablename, array('course' => 1));
3002         $DB->insert_record($tablename, array('course' => 2));
3003         $DB->insert_record($tablename, array('course' => 3));
3005         $this->assertTrue($DB->delete_records_list($tablename, 'course', array(2, 3)));
3006         $this->assertEqual(1, $DB->count_records($tablename));
3008         $this->assertTrue($DB->delete_records_list($tablename, 'course', array())); /// Must delete 0 rows without conditions. MDL-17645
3009         $this->assertEqual(1, $DB->count_records($tablename));
3010     }
3012     function test_sql_null_from_clause() {
3013         $DB = $this->tdb;
3014         $sql = "SELECT 1 AS id ".$DB->sql_null_from_clause();
3015         $this->assertEqual($DB->get_field_sql($sql), 1);
3016     }
3018     function test_sql_bitand() {
3019         $DB = $this->tdb;
3020         $dbman = $DB->get_manager();
3022         $table = $this->get_test_table();
3023         $tablename = $table->getName();
3025         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3026         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3027         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3028         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3029         $dbman->create_table($table);
3031         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
3033         $sql = "SELECT ".$DB->sql_bitand(10, 3)." AS res ".$DB->sql_null_from_clause();
3034         $this->assertEqual($DB->get_field_sql($sql), 2);
3036         $sql = "SELECT id, ".$DB->sql_bitand('col1', 'col2')." AS res FROM {{$tablename}}";
3037         $result = $DB->get_records_sql($sql);
3038         $this->assertEqual(count($result), 1);
3039         $this->assertEqual(reset($result)->res, 2);
3041         $sql = "SELECT id, ".$DB->sql_bitand('col1', '?')." AS res FROM {{$tablename}}";
3042         $result = $DB->get_records_sql($sql, array(10));
3043         $this->assertEqual(count($result), 1);
3044         $this->assertEqual(reset($result)->res, 2);
3045     }
3047     function test_sql_bitnot() {
3048         $DB = $this->tdb;
3050         $not = $DB->sql_bitnot(2);
3051         $notlimited = $DB->sql_bitand($not, 7); // might be positive or negative number which can not fit into PHP INT!
3053         $sql = "SELECT $notlimited AS res ".$DB->sql_null_from_clause();
3054         $this->assertEqual($DB->get_field_sql($sql), 5);
3055     }
3057     function test_sql_bitor() {
3058         $DB = $this->tdb;
3059         $dbman = $DB->get_manager();
3061         $table = $this->get_test_table();
3062         $tablename = $table->getName();
3064         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3065         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3066         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3067         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3068         $dbman->create_table($table);
3070         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
3072         $sql = "SELECT ".$DB->sql_bitor(10, 3)." AS res ".$DB->sql_null_from_clause();
3073         $this->assertEqual($DB->get_field_sql($sql), 11);
3075         $sql = "SELECT id, ".$DB->sql_bitor('col1', 'col2')." AS res FROM {{$tablename}}";
3076         $result = $DB->get_records_sql($sql);
3077         $this->assertEqual(count($result), 1);
3078         $this->assertEqual(reset($result)->res, 11);
3080         $sql = "SELECT id, ".$DB->sql_bitor('col1', '?')." AS res FROM {{$tablename}}";
3081         $result = $DB->get_records_sql($sql, array(10));
3082         $this->assertEqual(count($result), 1);
3083         $this->assertEqual(reset($result)->res, 11);
3084     }
3086     function test_sql_bitxor() {
3087         $DB = $this->tdb;
3088         $dbman = $DB->get_manager();
3090         $table = $this->get_test_table();
3091         $tablename = $table->getName();
3093         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3094         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3095         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3096         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3097         $dbman->create_table($table);
3099         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
3101         $sql = "SELECT ".$DB->sql_bitxor(10, 3)." AS res ".$DB->sql_null_from_clause();
3102         $this->assertEqual($DB->get_field_sql($sql), 9);
3104         $sql = "SELECT id, ".$DB->sql_bitxor('col1', 'col2')." AS res FROM {{$tablename}}";
3105         $result = $DB->get_records_sql($sql);
3106         $this->assertEqual(count($result), 1);
3107         $this->assertEqual(reset($result)->res, 9);
3109         $sql = "SELECT id, ".$DB->sql_bitxor('col1', '?')." AS res FROM {{$tablename}}";
3110         $result = $DB->get_records_sql($sql, array(10));
3111         $this->assertEqual(count($result), 1);
3112         $this->assertEqual(reset($result)->res, 9);
3113     }
3115     function test_sql_modulo() {
3116         $DB = $this->tdb;
3117         $sql = "SELECT ".$DB->sql_modulo(10, 7)." AS res ".$DB->sql_null_from_clause();
3118         $this->assertEqual($DB->get_field_sql($sql), 3);
3119     }
3121     function test_sql_ceil() {
3122         $DB = $this->tdb;
3123         $sql = "SELECT ".$DB->sql_ceil(665.666)." AS res ".$DB->sql_null_from_clause();
3124         $this->assertEqual($DB->get_field_sql($sql), 666);
3125     }
3127     function test_cast_char2int() {
3128         $DB = $this->tdb;
3129         $dbman = $DB->get_manager();
3131         $table1 = $this->get_test_table("1");
3132         $tablename1 = $table1->getName();
3134         $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3135         $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3136         $table1->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
3137         $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3138         $dbman->create_table($table1);
3140         $DB->insert_record($tablename1, array('name'=>'0100', 'nametext'=>'0200'));
3141         $DB->insert_record($tablename1, array('name'=>'10',   'nametext'=>'20'));
3143         $table2 = $this->get_test_table("2");
3144         $tablename2 = $table2->getName();
3145         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3146         $table2->add_field('res', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3147         $table2->add_field('restext', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3148         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3149         $dbman->create_table($table2);
3151         $DB->insert_record($tablename2, array('res'=>100, 'restext'=>200));
3153         // casting varchar field
3154         $sql = "SELECT *
3155                   FROM {".$tablename1."} t1
3156                   JOIN {".$tablename2."} t2 ON ".$DB->sql_cast_char2int("t1.name")." = t2.res ";
3157         $records = $DB->get_records_sql($sql);
3158         $this->assertEqual(count($records), 1);
3159         // also test them in order clauses
3160         $sql = "SELECT * FROM {{$tablename1}} ORDER BY ".$DB->sql_cast_char2int('name');
3161         $records = $DB->get_records_sql($sql);
3162         $this->assertEqual(count($records), 2);
3163         $this->assertEqual(reset($records)->name, '10');
3164         $this->assertEqual(next($records)->name, '0100');
3166         // casting text field
3167         $sql = "SELECT *
3168                   FROM {".$tablename1."} t1
3169                   JOIN {".$tablename2."} t2 ON ".$DB->sql_cast_char2int("t1.nametext", true)." = t2.restext ";
3170         $records = $DB->get_records_sql($sql);
3171         $this->assertEqual(count($records), 1);
3172         // also test them in order clauses
3173         $sql = "SELECT * FROM {{$tablename1}} ORDER BY ".$DB->sql_cast_char2int('nametext', true);
3174         $records = $DB->get_records_sql($sql);
3175         $this->assertEqual(count($records), 2);
3176         $this->assertEqual(reset($records)->nametext, '20');
3177         $this->assertEqual(next($records)->nametext, '0200');
3178     }
3180     function test_cast_char2real() {
3181         $DB = $this->tdb;
3182         $dbman = $DB->get_manager();
3184         $table = $this->get_test_table();
3185         $tablename = $table->getName();
3187         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3188         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3189         $table->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
3190         $table->add_field('res', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null);
3191         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3192         $dbman->create_table($table);
3194         $DB->insert_record($tablename, array('name'=>'10.10', 'nametext'=>'10.10', 'res'=>5.1));
3195         $DB->insert_record($tablename, array('name'=>'91.10', 'nametext'=>'91.10', 'res'=>666));
3196         $DB->insert_record($tablename, array('name'=>'011.10','nametext'=>'011.10','res'=>10.1));
3198         // casting varchar field
3199         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_cast_char2real('name')." > res";
3200         $records = $DB->get_records_sql($sql);
3201         $this->assertEqual(count($records), 2);
3202         // also test them in order clauses
3203         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_cast_char2real('name');
3204         $records = $DB->get_records_sql($sql);
3205         $this->assertEqual(count($records), 3);
3206         $this->assertEqual(reset($records)->name, '10.10');
3207         $this->assertEqual(next($records)->name, '011.10');
3208         $this->assertEqual(next($records)->name, '91.10');
3210         // casting text field
3211         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_cast_char2real('nametext', true)." > res";
3212         $records = $DB->get_records_sql($sql);
3213         $this->assertEqual(count($records), 2);
3214         // also test them in order clauses
3215         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_cast_char2real('nametext', true);
3216         $records = $DB->get_records_sql($sql);
3217         $this->assertEqual(count($records), 3);
3218         $this->assertEqual(reset($records)->nametext, '10.10');
3219         $this->assertEqual(next($records)->nametext, '011.10');
3220         $this->assertEqual(next($records)->nametext, '91.10');
3221     }
3223     function sql_compare_text() {
3224         $DB = $this->tdb;
3225         $dbman = $DB->get_manager();
3227         $table = $this->get_test_table();
3228         $tablename = $table->getName();
3230         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3231         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3232         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
3233         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3234         $dbman->create_table($table);
3236         $DB->insert_record($tablename, array('name'=>'abcd',   'description'=>'abcd'));
3237         $DB->insert_record($tablename, array('name'=>'abcdef', 'description'=>'bbcdef'));
3238         $DB->insert_record($tablename, array('name'=>'aaaabb', 'description'=>'aaaacccccccccccccccccc'));
3240         $sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description');
3241         $records = $DB->get_records_sql($sql);
3242         $this->assertEqual(count($records), 1);
3244         $sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description', 4);
3245         $records = $DB->get_records_sql($sql);
3246         $this->assertEqual(count($records), 2);
3247     }
3249     function test_unique_index_collation_trouble() {
3250         // note: this is a work in progress, we should probably move this to ddl test
3252         $DB = $this->tdb;
3253         $dbman = $DB->get_manager();
3255         $table = $this->get_test_table();
3256         $tablename = $table->getName();
3258         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3259         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3260         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3261         $table->add_index('name', XMLDB_INDEX_UNIQUE, array('name'));
3262         $dbman->create_table($table);
3264         $DB->insert_record($tablename, array('name'=>'aaa'));
3266         try {
3267             $DB->insert_record($tablename, array('name'=>'AAA'));
3268         } catch (Exception $e) {
3269             //TODO: ignore case insensitive uniqueness problems for&n