MDL-23925, MDL-23888 new sql_ilike() and sql_binary_equal() - this should finally...
[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    moodlecore
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 if (!defined('MOODLE_INTERNAL')) {
26     die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
27 }
29 class dml_test extends UnitTestCase {
30     private $tables = array();
31     private $tdb;
32     private $data;
33     public  static $includecoverage = array('lib/dml');
34     public  static $excludecoverage = array('lib/dml/simpletest');
36     function setUp() {
37         global $CFG, $DB, $UNITTEST;
39         if (isset($UNITTEST->func_test_db)) {
40             $this->tdb = $UNITTEST->func_test_db;
41         } else {
42             $this->tdb = $DB;
43         }
45     }
47     function tearDown() {
48         $dbman = $this->tdb->get_manager();
50         foreach ($this->tables as $table) {
51             if ($dbman->table_exists($table)) {
52                 $dbman->drop_table($table);
53             }
54         }
55         $this->tables = array();
56     }
58     /**
59      * Get a xmldb_table object for testing, deleting any existing table
60      * of the same name, for example if one was left over from a previous test
61      * run that crashed.
62      *
63      * @param database_manager $dbman the database_manager to use.
64      * @param string $tablename the name of the table to create.
65      * @return xmldb_table the table object.
66      */
67     private function get_test_table($tablename="") {
68         $DB = $this->tdb;
69         $dbman = $this->tdb->get_manager();
71         if ($tablename == '') {
72             $tablename = "unit_table";
73         }
75         $table = new xmldb_table($tablename);
76         if ($dbman->table_exists($table)) {
77             $dbman->drop_table($table);
78         }
79         return new xmldb_table($tablename);
80     }
82     function test_fix_sql_params() {
83         $DB = $this->tdb;
85         $table = $this->get_test_table();
86         $tablename = $table->getName();
88         // Correct table placeholder substitution
89         $sql = "SELECT * FROM {".$tablename."}";
90         $sqlarray = $DB->fix_sql_params($sql);
91         $this->assertEqual("SELECT * FROM {$DB->get_prefix()}".$tablename, $sqlarray[0]);
93         // Conversions of all param types
94         $sql = array();
95         $sql[SQL_PARAMS_NAMED]  = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = :param1, course = :param2";
96         $sql[SQL_PARAMS_QM]     = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = ?, course = ?";
97         $sql[SQL_PARAMS_DOLLAR] = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = \$1, course = \$2";
99         $params = array();
100         $params[SQL_PARAMS_NAMED]  = array('param1'=>'first record', 'param2'=>1);
101         $params[SQL_PARAMS_QM]     = array('first record', 1);
102         $params[SQL_PARAMS_DOLLAR] = array('first record', 1);
104         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_NAMED], $params[SQL_PARAMS_NAMED]);
105         $this->assertEqual($rsql, $sql[$rtype]);
106         $this->assertEqual($rparams, $params[$rtype]);
108         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_QM], $params[SQL_PARAMS_QM]);
109         $this->assertEqual($rsql, $sql[$rtype]);
110         $this->assertEqual($rparams, $params[$rtype]);
112         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_DOLLAR], $params[SQL_PARAMS_DOLLAR]);
113         $this->assertEqual($rsql, $sql[$rtype]);
114         $this->assertEqual($rparams, $params[$rtype]);
117         // Malformed table placeholder
118         $sql = "SELECT * FROM [testtable]";
119         $sqlarray = $DB->fix_sql_params($sql);
120         $this->assertEqual($sql, $sqlarray[0]);
123         // Mixed param types (colon and dollar)
124         $sql = "SELECT * FROM {".$tablename."} WHERE name = :param1, course = \$1";
125         $params = array('param1' => 'record1', 'param2' => 3);
126         try {
127             $sqlarray = $DB->fix_sql_params($sql, $params);
128             $this->fail("Expecting an exception, none occurred");
129         } catch (Exception $e) {
130             $this->assertTrue($e instanceof moodle_exception);
131         }
133         // Mixed param types (question and dollar)
134         $sql = "SELECT * FROM {".$tablename."} WHERE name = ?, course = \$1";
135         $params = array('param1' => 'record2', 'param2' => 5);
136         try {
137             $sqlarray = $DB->fix_sql_params($sql, $params);
138             $this->fail("Expecting an exception, none occurred");
139         } catch (Exception $e) {
140             $this->assertTrue($e instanceof moodle_exception);
141         }
143         // Too many params in sql
144         $sql = "SELECT * FROM {".$tablename."} WHERE name = ?, course = ?, id = ?";
145         $params = array('record2', 3);
146         try {
147             $sqlarray = $DB->fix_sql_params($sql, $params);
148             $this->fail("Expecting an exception, none occurred");
149         } catch (Exception $e) {
150             $this->assertTrue($e instanceof moodle_exception);
151         }
153         // Too many params in array: no error
154         $params[] = 1;
155         $params[] = time();
156         $sqlarray = null;
158         try {
159             $sqlarray = $DB->fix_sql_params($sql, $params);
160             $this->pass();
161         } catch (Exception $e) {
162             $this->fail("Unexpected ".get_class($e)." exception");
163         }
164         $this->assertTrue($sqlarray[0]);
166         // Named params missing from array
167         $sql = "SELECT * FROM {".$tablename."} WHERE name = :name, course = :course";
168         $params = array('wrongname' => 'record1', 'course' => 1);
169         try {
170             $sqlarray = $DB->fix_sql_params($sql, $params);
171             $this->fail("Expecting an exception, none occurred");
172         } catch (Exception $e) {
173             $this->assertTrue($e instanceof moodle_exception);
174         }
176         // Duplicate named param in query
177         $sql = "SELECT * FROM {".$tablename."} WHERE name = :name, course = :name";
178         $params = array('name' => 'record2', 'course' => 3);
179         try {
180             $sqlarray = $DB->fix_sql_params($sql, $params);
181             $this->fail("Expecting an exception, none occurred");
182         } catch (Exception $e) {
183             $this->assertTrue($e instanceof moodle_exception);
184         }
186     }
188     public function testGetTables() {
189         $DB = $this->tdb;
190         $dbman = $this->tdb->get_manager();
192         // Need to test with multiple DBs
193         $table = $this->get_test_table();
194         $tablename = $table->getName();
196         $original_count = count($DB->get_tables());
198         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
199         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
200         $dbman->create_table($table);
201         $this->tables[$tablename] = $table;
203         $this->assertTrue(count($DB->get_tables()) == $original_count + 1);
204     }
206     public function testDefaults() {
207         $DB = $this->tdb;
208         $dbman = $this->tdb->get_manager();
210         $table = $this->get_test_table();
211         $tablename = $table->getName();
213         $table->add_field('enumfield', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'test2');
214         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
215         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
216         $dbman->create_table($table);
217         $this->tables[$tablename] = $table;
219         $columns = $DB->get_columns($tablename);
221         $enumfield = $columns['enumfield'];
222         $this->assertEqual('test2', $enumfield->default_value);
223         $this->assertEqual('C', $enumfield->meta_type);
225     }
227     public function testGetIndexes() {
228         $DB = $this->tdb;
229         $dbman = $this->tdb->get_manager();
231         $table = $this->get_test_table();
232         $tablename = $table->getName();
234         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
235         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
236         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
237         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
238         $table->add_index('course-id', XMLDB_INDEX_UNIQUE, array('course', 'id'));
239         $dbman->create_table($table);
240         $this->tables[$tablename] = $table;
242         $this->assertTrue($indices = $DB->get_indexes($tablename));
243         $this->assertEqual(count($indices), 2);
244         // we do not care about index names for now
245         $first = array_shift($indices);
246         $second = array_shift($indices);
247         if (count($first['columns']) == 2) {
248             $composed = $first;
249             $single   = $second;
250         } else {
251             $composed = $second;
252             $single   = $first;
253         }
254         $this->assertFalse($single['unique']);
255         $this->assertTrue($composed['unique']);
256         $this->assertEqual(1, count($single['columns']));
257         $this->assertEqual(2, count($composed['columns']));
258         $this->assertEqual('course', $single['columns'][0]);
259         $this->assertEqual('course', $composed['columns'][0]);
260         $this->assertEqual('id', $composed['columns'][1]);
261     }
263     public function testGetColumns() {
264         $DB = $this->tdb;
265         $dbman = $this->tdb->get_manager();
267         $table = $this->get_test_table();
268         $tablename = $table->getName();
270         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
271         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
272         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
273         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
274         $dbman->create_table($table);
275         $this->tables[$tablename] = $table;
277         $this->assertTrue($columns = $DB->get_columns($tablename));
278         $fields = $this->tables[$tablename]->getFields();
279         $this->assertEqual(count($columns), count($fields));
281         for ($i = 0; $i < count($columns); $i++) {
282             if ($i == 0) {
283                 $next_column = reset($columns);
284                 $next_field  = reset($fields);
285             } else {
286                 $next_column = next($columns);
287                 $next_field  = next($fields);
288             }
290             $this->assertEqual($next_column->name, $next_field->name);
291         }
292     }
294     public function testExecute() {
295         $DB = $this->tdb;
296         $dbman = $this->tdb->get_manager();
298         $table = $this->get_test_table();
299         $tablename = $table->getName();
301         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
302         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
303         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
304         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
305         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
306         $dbman->create_table($table);
307         $this->tables[$tablename] = $table;
309         $sql = "SELECT * FROM {".$tablename."}";
311         $this->assertTrue($DB->execute($sql));
313         $params = array('course' => 1, 'name' => 'test');
315         $sql = "INSERT INTO {".$tablename."} (".implode(',', array_keys($params)).")
316                        VALUES (".implode(',', array_fill(0, count($params), '?')).")";
319         $this->assertTrue($DB->execute($sql, $params));
321         $record = $DB->get_record($tablename, array('id' => 1));
323         foreach ($params as $field => $value) {
324             $this->assertEqual($value, $record->$field, "Field $field in DB ({$record->$field}) is not equal to field $field in sql ($value)");
325         }
326     }
328     public function test_get_in_or_equal() {
329         $DB = $this->tdb;
331         // SQL_PARAMS_QM - IN or =
333         // Correct usage of multiple values
334         $in_values = array('value1', 'value2', 'value3', 'value4');
335         list($usql, $params) = $DB->get_in_or_equal($in_values);
336         $this->assertEqual("IN (?,?,?,?)", $usql);
337         $this->assertEqual(4, count($params));
338         foreach ($params as $key => $value) {
339             $this->assertEqual($in_values[$key], $value);
340         }
342         // Correct usage of single value (in an array)
343         $in_values = array('value1');
344         list($usql, $params) = $DB->get_in_or_equal($in_values);
345         $this->assertEqual("= ?", $usql);
346         $this->assertEqual(1, count($params));
347         $this->assertEqual($in_values[0], $params[0]);
349         // Correct usage of single value
350         $in_value = 'value1';
351         list($usql, $params) = $DB->get_in_or_equal($in_values);
352         $this->assertEqual("= ?", $usql);
353         $this->assertEqual(1, count($params));
354         $this->assertEqual($in_value, $params[0]);
356         // SQL_PARAMS_QM - NOT IN or <>
358         // Correct usage of multiple values
359         $in_values = array('value1', 'value2', 'value3', 'value4');
360         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
361         $this->assertEqual("NOT IN (?,?,?,?)", $usql);
362         $this->assertEqual(4, count($params));
363         foreach ($params as $key => $value) {
364             $this->assertEqual($in_values[$key], $value);
365         }
367         // Correct usage of single value (in array()
368         $in_values = array('value1');
369         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
370         $this->assertEqual("<> ?", $usql);
371         $this->assertEqual(1, count($params));
372         $this->assertEqual($in_values[0], $params[0]);
374         // Correct usage of single value
375         $in_value = 'value1';
376         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
377         $this->assertEqual("<> ?", $usql);
378         $this->assertEqual(1, count($params));
379         $this->assertEqual($in_value, $params[0]);
381         // SQL_PARAMS_NAMED - IN or =
383         // Correct usage of multiple values
384         $in_values = array('value1', 'value2', 'value3', 'value4');
385         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', true);
386         $this->assertEqual("IN (:param01,:param02,:param03,:param04)", $usql);
387         $this->assertEqual(4, count($params));
388         reset($in_values);
389         foreach ($params as $key => $value) {
390             $this->assertEqual(current($in_values), $value);
391             next($in_values);
392         }
394         // Correct usage of single values (in array)
395         $in_values = array('value1');
396         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', true);
397         $this->assertEqual("= :param01", $usql);
398         $this->assertEqual(1, count($params));
399         $this->assertEqual($in_values[0], $params['param01']);
401         // Correct usage of single value
402         $in_value = 'value1';
403         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', true);
404         $this->assertEqual("= :param01", $usql);
405         $this->assertEqual(1, count($params));
406         $this->assertEqual($in_value, $params['param01']);
408         // SQL_PARAMS_NAMED - NOT IN or <>
410         // Correct usage of multiple values
411         $in_values = array('value1', 'value2', 'value3', 'value4');
412         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
413         $this->assertEqual("NOT IN (:param01,:param02,:param03,:param04)", $usql);
414         $this->assertEqual(4, count($params));
415         reset($in_values);
416         foreach ($params as $key => $value) {
417             $this->assertEqual(current($in_values), $value);
418             next($in_values);
419         }
421         // Correct usage of single values (in array)
422         $in_values = array('value1');
423         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
424         $this->assertEqual("<> :param01", $usql);
425         $this->assertEqual(1, count($params));
426         $this->assertEqual($in_values[0], $params['param01']);
428         // Correct usage of single value
429         $in_value = 'value1';
430         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
431         $this->assertEqual("<> :param01", $usql);
432         $this->assertEqual(1, count($params));
433         $this->assertEqual($in_value, $params['param01']);
435     }
437     public function test_fix_table_names() {
438         $DB = new moodle_database_for_testing();
439         $prefix = $DB->get_prefix();
441         // Simple placeholder
442         $placeholder = "{user}";
443         $this->assertEqual($prefix."user", $DB->public_fix_table_names($placeholder));
445         // Full SQL
446         $sql = "SELECT * FROM {user}, {funny_table_name}, {mdl_stupid_table} WHERE {user}.id = {funny_table_name}.userid";
447         $expected = "SELECT * FROM {$prefix}user, {$prefix}funny_table_name, {$prefix}mdl_stupid_table WHERE {$prefix}user.id = {$prefix}funny_table_name.userid";
448         $this->assertEqual($expected, $DB->public_fix_table_names($sql));
451     }
453     public function test_get_recordset() {
454         $DB = $this->tdb;
455         $dbman = $DB->get_manager();
457         $table = $this->get_test_table();
458         $tablename = $table->getName();
460         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
461         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
462         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
463         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
464         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
465         $dbman->create_table($table);
466         $this->tables[$tablename] = $table;
468         $data = array(array('id' => 1, 'course' => 3, 'name' => 'record1'),
469                       array('id' => 2, 'course' => 3, 'name' => 'record2'),
470                       array('id' => 3, 'course' => 5, 'name' => 'record3'));
472         foreach ($data as $record) {
473             $DB->insert_record($tablename, $record);
474         }
476         $rs = $DB->get_recordset($tablename);
477         $this->assertTrue($rs);
479         reset($data);
480         foreach($rs as $record) {
481             $data_record = current($data);
482             foreach ($record as $k => $v) {
483                 $this->assertEqual($data_record[$k], $v);
484             }
485             next($data);
486         }
487         $rs->close();
489         // note: delegate limits testing to test_get_recordset_sql()
490     }
492     public function test_get_recordset_iterator_keys() {
493         $DB = $this->tdb;
494         $dbman = $DB->get_manager();
496         $table = $this->get_test_table();
497         $tablename = $table->getName();
499         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
500         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
501         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
502         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
503         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
504         $dbman->create_table($table);
505         $this->tables[$tablename] = $table;
507         $data = array(array('id'=> 1, 'course' => 3, 'name' => 'record1'),
508                       array('id'=> 2, 'course' => 3, 'name' => 'record2'),
509                       array('id'=> 3, 'course' => 5, 'name' => 'record3'));
510         foreach ($data as $record) {
511             $DB->insert_record($tablename, $record);
512         }
514     /// Test repeated numeric keys are returned ok
515         $rs = $DB->get_recordset($tablename, NULL, NULL, 'course, name, id');
517         reset($data);
518         $count = 0;
519         foreach($rs as $key => $record) {
520             $data_record = current($data);
521             $this->assertEqual($data_record['course'], $key);
522             next($data);
523             $count++;
524         }
525         $rs->close();
527     /// Test record returned are ok
528         $this->assertEqual($count, 3);
530     /// Test string keys are returned ok
531         $rs = $DB->get_recordset($tablename, NULL, NULL, 'name, course, id');
533         reset($data);
534         $count = 0;
535         foreach($rs as $key => $record) {
536             $data_record = current($data);
537             $this->assertEqual($data_record['name'], $key);
538             next($data);
539             $count++;
540         }
541         $rs->close();
543     /// Test record returned are ok
544         $this->assertEqual($count, 3);
546     /// Test numeric not starting in 1 keys are returned ok
547         $rs = $DB->get_recordset($tablename, NULL, 'id DESC', 'id, course, name');
549         $data = array_reverse($data);
550         reset($data);
551         $count = 0;
552         foreach($rs as $key => $record) {
553             $data_record = current($data);
554             $this->assertEqual($data_record['id'], $key);
555             next($data);
556             $count++;
557         }
558         $rs->close();
560     /// Test record returned are ok
561         $this->assertEqual($count, 3);
562     }
564     public function test_get_recordset_list() {
565         $DB = $this->tdb;
566         $dbman = $DB->get_manager();
568         $table = $this->get_test_table();
569         $tablename = $table->getName();
571         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
572         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
573         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
574         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
575         $dbman->create_table($table);
576         $this->tables[$tablename] = $table;
578         $DB->insert_record($tablename, array('course' => 3));
579         $DB->insert_record($tablename, array('course' => 3));
580         $DB->insert_record($tablename, array('course' => 5));
581         $DB->insert_record($tablename, array('course' => 2));
583         $rs = $DB->get_recordset_list($tablename, 'course', array(3, 2));
585         $this->assertTrue($rs);
587         $counter = 0;
588         foreach ($rs as $record) {
589             $counter++;
590         }
591         $this->assertEqual(3, $counter);
592         $rs->close();
594         $rs = $DB->get_recordset_list($tablename, 'course',array()); /// Must return 0 rows without conditions. MDL-17645
596         $counter = 0;
597         foreach ($rs as $record) {
598             $counter++;
599         }
600         $rs->close();
601         $this->assertEqual(0, $counter);
603         // note: delegate limits testing to test_get_recordset_sql()
604     }
606     public function test_get_recordset_select() {
607         $DB = $this->tdb;
608         $dbman = $DB->get_manager();
610         $table = $this->get_test_table();
611         $tablename = $table->getName();
613         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
614         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
615         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
616         $dbman->create_table($table);
617         $this->tables[$tablename] = $table;
619         $DB->insert_record($tablename, array('course' => 3));
620         $DB->insert_record($tablename, array('course' => 3));
621         $DB->insert_record($tablename, array('course' => 5));
622         $DB->insert_record($tablename, array('course' => 2));
624         $rs = $DB->get_recordset_select($tablename, '');
625         $counter = 0;
626         foreach ($rs as $record) {
627             $counter++;
628         }
629         $rs->close();
630         $this->assertEqual(4, $counter);
632         $this->assertTrue($rs = $DB->get_recordset_select($tablename, 'course = 3'));
633         $counter = 0;
634         foreach ($rs as $record) {
635             $counter++;
636         }
637         $rs->close();
638         $this->assertEqual(2, $counter);
640         // note: delegate limits testing to test_get_recordset_sql()
641     }
643     public function test_get_recordset_sql() {
644         $DB = $this->tdb;
645         $dbman = $DB->get_manager();
647         $table = $this->get_test_table();
648         $tablename = $table->getName();
650         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
651         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
652         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
653         $dbman->create_table($table);
654         $this->tables[$tablename] = $table;
656         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
657         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
658         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
659         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
660         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
661         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
662         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
664         $this->assertTrue($rs = $DB->get_recordset_sql("SELECT * FROM {".$tablename."} WHERE course = ?", array(3)));
665         $counter = 0;
666         foreach ($rs as $record) {
667             $counter++;
668         }
669         $rs->close();
670         $this->assertEqual(2, $counter);
672         // limits - only need to test this case, the rest have been tested by test_get_records_sql()
673         // only limitfrom = skips that number of records
674         $rs = $DB->get_recordset_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 2, 0);
675         $records = array();
676         foreach($rs as $key => $record) {
677             $records[$key] = $record;
678         }
679         $rs->close();
680         $this->assertEqual(5, count($records));
681         $this->assertEqual($inskey3, reset($records)->id);
682         $this->assertEqual($inskey7, end($records)->id);
684         // note: fetching nulls, empties, LOBs already tested by test_insert_record() no needed here
685     }
687     public function test_get_records() {
688         $DB = $this->tdb;
689         $dbman = $DB->get_manager();
691         $table = $this->get_test_table();
692         $tablename = $table->getName();
694         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
695         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
696         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
697         $dbman->create_table($table);
698         $this->tables[$tablename] = $table;
700         $DB->insert_record($tablename, array('course' => 3));
701         $DB->insert_record($tablename, array('course' => 3));
702         $DB->insert_record($tablename, array('course' => 5));
703         $DB->insert_record($tablename, array('course' => 2));
705         // All records
706         $records = $DB->get_records($tablename);
707         $this->assertEqual(4, count($records));
708         $this->assertEqual(3, $records[1]->course);
709         $this->assertEqual(3, $records[2]->course);
710         $this->assertEqual(5, $records[3]->course);
711         $this->assertEqual(2, $records[4]->course);
713         // Records matching certain conditions
714         $records = $DB->get_records($tablename, array('course' => 3));
715         $this->assertEqual(2, count($records));
716         $this->assertEqual(3, $records[1]->course);
717         $this->assertEqual(3, $records[2]->course);
719         // All records sorted by course
720         $records = $DB->get_records($tablename, null, 'course');
721         $this->assertEqual(4, count($records));
722         $current_record = reset($records);
723         $this->assertEqual(4, $current_record->id);
724         $current_record = next($records);
725         $this->assertEqual(1, $current_record->id);
726         $current_record = next($records);
727         $this->assertEqual(2, $current_record->id);
728         $current_record = next($records);
729         $this->assertEqual(3, $current_record->id);
731         // All records, but get only one field
732         $records = $DB->get_records($tablename, null, '', 'id');
733         $this->assertTrue(empty($records[1]->course));
734         $this->assertFalse(empty($records[1]->id));
735         $this->assertEqual(4, count($records));
737         // note: delegate limits testing to test_get_records_sql()
738     }
740     public function test_get_records_list() {
741         $DB = $this->tdb;
742         $dbman = $DB->get_manager();
744         $table = $this->get_test_table();
745         $tablename = $table->getName();
747         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
748         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
749         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
750         $dbman->create_table($table);
751         $this->tables[$tablename] = $table;
753         $DB->insert_record($tablename, array('course' => 3));
754         $DB->insert_record($tablename, array('course' => 3));
755         $DB->insert_record($tablename, array('course' => 5));
756         $DB->insert_record($tablename, array('course' => 2));
758         $this->assertTrue($records = $DB->get_records_list($tablename, 'course', array(3, 2)));
759         $this->assertEqual(3, count($records));
760         $this->assertEqual(1, reset($records)->id);
761         $this->assertEqual(2, next($records)->id);
762         $this->assertEqual(4, next($records)->id);
764         $this->assertIdentical(array(), $records = $DB->get_records_list($tablename, 'course', array())); /// Must return 0 rows without conditions. MDL-17645
765         $this->assertEqual(0, count($records));
767         // note: delegate limits testing to test_get_records_sql()
768     }
770     public function test_get_record_select() {
771         $DB = $this->tdb;
772         $dbman = $DB->get_manager();
774         $table = $this->get_test_table();
775         $tablename = $table->getName();
777         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
778         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
779         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
780         $dbman->create_table($table);
781         $this->tables[$tablename] = $table;
783         $DB->insert_record($tablename, array('course' => 3));
784         $DB->insert_record($tablename, array('course' => 2));
786         $this->assertTrue($record = $DB->get_record_select($tablename, "id = ?", array(2)));
788         $this->assertEqual(2, $record->course);
790         // note: delegates limit testing to test_get_records_sql()
791     }
793     public function test_get_records_sql() {
794         global $CFG;
795         $DB = $this->tdb;
796         $dbman = $DB->get_manager();
798         $table = $this->get_test_table();
799         $tablename = $table->getName();
801         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
802         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
803         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
804         $dbman->create_table($table);
805         $this->tables[$tablename] = $table;
807         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
808         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
809         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
810         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
811         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
812         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
813         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
815         $this->assertTrue($records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE course = ?", array(3)));
816         $this->assertEqual(2, count($records));
817         $this->assertEqual($inskey1, reset($records)->id);
818         $this->assertEqual($inskey4, next($records)->id);
820         // Awful test, requires debug enabled and sent to browser. Let's do that and restore after test
821         $olddebug   = $CFG->debug;       // Save current debug settings
822         $olddisplay = $CFG->debugdisplay;
823         $CFG->debug = DEBUG_DEVELOPER;
824         $CFG->debugdisplay = true;
825         ob_start(); // hide debug warning
826         $records = $DB->get_records_sql("SELECT course AS id, course AS course FROM {".$tablename."}", null);
827         ob_end_clean();
828         $debuginfo = ob_get_contents();
829         $CFG->debug = $olddebug;         // Restore original debug settings
830         $CFG->debugdisplay = $olddisplay;
832         $this->assertEqual(6, count($records));
833         $this->assertFalse($debuginfo === '');
835         // negative limits = no limits
836         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, -1, -1);
837         $this->assertEqual(7, count($records));
839         // zero limits = no limits
840         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 0, 0);
841         $this->assertEqual(7, count($records));
843         // only limitfrom = skips that number of records
844         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 2, 0);
845         $this->assertEqual(5, count($records));
846         $this->assertEqual($inskey3, reset($records)->id);
847         $this->assertEqual($inskey7, end($records)->id);
849         // only limitnum = fetches that number of records
850         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 0, 3);
851         $this->assertEqual(3, count($records));
852         $this->assertEqual($inskey1, reset($records)->id);
853         $this->assertEqual($inskey3, end($records)->id);
855         // both limitfrom and limitnum = skips limitfrom records and fetches limitnum ones
856         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 3, 2);
857         $this->assertEqual(2, count($records));
858         $this->assertEqual($inskey4, reset($records)->id);
859         $this->assertEqual($inskey5, end($records)->id);
861         // note: fetching nulls, empties, LOBs already tested by test_update_record() no needed here
862     }
864     public function test_get_records_menu() {
865         $DB = $this->tdb;
866         $dbman = $DB->get_manager();
868         $table = $this->get_test_table();
869         $tablename = $table->getName();
871         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
872         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
873         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
874         $dbman->create_table($table);
875         $this->tables[$tablename] = $table;
877         $DB->insert_record($tablename, array('course' => 3));
878         $DB->insert_record($tablename, array('course' => 3));
879         $DB->insert_record($tablename, array('course' => 5));
880         $DB->insert_record($tablename, array('course' => 2));
882         $this->assertTrue($records = $DB->get_records_menu($tablename, array('course' => 3)));
883         $this->assertEqual(2, count($records));
884         $this->assertFalse(empty($records[1]));
885         $this->assertFalse(empty($records[2]));
886         $this->assertEqual(3, $records[1]);
887         $this->assertEqual(3, $records[2]);
889         // note: delegate limits testing to test_get_records_sql()
890     }
892     public function test_get_records_select_menu() {
893         $DB = $this->tdb;
894         $dbman = $DB->get_manager();
896         $table = $this->get_test_table();
897         $tablename = $table->getName();
899         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
900         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
901         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
902         $dbman->create_table($table);
903         $this->tables[$tablename] = $table;
905         $DB->insert_record($tablename, array('course' => 3));
906         $DB->insert_record($tablename, array('course' => 2));
907         $DB->insert_record($tablename, array('course' => 3));
908         $DB->insert_record($tablename, array('course' => 5));
910         $this->assertTrue($records = $DB->get_records_select_menu($tablename, "course > ?", array(2)));
912         $this->assertEqual(3, count($records));
913         $this->assertFalse(empty($records[1]));
914         $this->assertTrue(empty($records[2]));
915         $this->assertFalse(empty($records[3]));
916         $this->assertFalse(empty($records[4]));
917         $this->assertEqual(3, $records[1]);
918         $this->assertEqual(3, $records[3]);
919         $this->assertEqual(5, $records[4]);
921         // note: delegate limits testing to test_get_records_sql()
922     }
924     public function test_get_records_sql_menu() {
925         $DB = $this->tdb;
926         $dbman = $DB->get_manager();
928         $table = $this->get_test_table();
929         $tablename = $table->getName();
931         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
932         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
933         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
934         $dbman->create_table($table);
935         $this->tables[$tablename] = $table;
937         $DB->insert_record($tablename, array('course' => 3));
938         $DB->insert_record($tablename, array('course' => 2));
939         $DB->insert_record($tablename, array('course' => 3));
940         $DB->insert_record($tablename, array('course' => 5));
942         $this->assertTrue($records = $DB->get_records_sql_menu("SELECT * FROM {".$tablename."} WHERE course > ?", array(2)));
944         $this->assertEqual(3, count($records));
945         $this->assertFalse(empty($records[1]));
946         $this->assertTrue(empty($records[2]));
947         $this->assertFalse(empty($records[3]));
948         $this->assertFalse(empty($records[4]));
949         $this->assertEqual(3, $records[1]);
950         $this->assertEqual(3, $records[3]);
951         $this->assertEqual(5, $records[4]);
953         // note: delegate limits testing to test_get_records_sql()
954     }
956     public function test_get_record() {
957         $DB = $this->tdb;
958         $dbman = $DB->get_manager();
960         $table = $this->get_test_table();
961         $tablename = $table->getName();
963         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
964         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
965         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
966         $dbman->create_table($table);
967         $this->tables[$tablename] = $table;
969         $DB->insert_record($tablename, array('course' => 3));
970         $DB->insert_record($tablename, array('course' => 2));
972         $this->assertTrue($record = $DB->get_record($tablename, array('id' => 2)));
974         $this->assertEqual(2, $record->course);
975     }
977     public function test_get_record_sql() {
978         $DB = $this->tdb;
979         $dbman = $DB->get_manager();
981         $table = $this->get_test_table();
982         $tablename = $table->getName();
984         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
985         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
986         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
987         $dbman->create_table($table);
988         $this->tables[$tablename] = $table;
990         $DB->insert_record($tablename, array('course' => 3));
991         $DB->insert_record($tablename, array('course' => 2));
993         $this->assertTrue($record = $DB->get_record_sql("SELECT * FROM {".$tablename."} WHERE id = ?", array(2)));
995         $this->assertEqual(2, $record->course);
997         // backwards compatibility with $ignoremultiple
998         $this->assertFalse(IGNORE_MISSING);
999         $this->assertTrue(IGNORE_MULTIPLE);
1001         // record not found
1002         $this->assertFalse($record = $DB->get_record_sql("SELECT * FROM {".$tablename."} WHERE id = ?", array(666), IGNORE_MISSING));
1003         $this->assertFalse($record = $DB->get_record_sql("SELECT * FROM {".$tablename."} WHERE id = ?", array(666), IGNORE_MULTIPLE));
1004         try {
1005             $DB->get_record_sql("SELECT * FROM {".$tablename."} WHERE id = ?", array(666), MUST_EXIST);
1006             $this->fail("Exception expected");
1007         } catch (dml_missing_record_exception $e) {
1008             $this->assertTrue(true);
1009         }
1011         // multiple matches
1012         ob_start(); // hide debug warning
1013         $this->assertTrue($record = $DB->get_record_sql("SELECT * FROM {".$tablename."}", array(), IGNORE_MISSING));
1014         ob_end_clean();
1015         $this->assertTrue($record = $DB->get_record_sql("SELECT * FROM {".$tablename."}", array(), IGNORE_MULTIPLE));
1016         try {
1017             $DB->get_record_sql("SELECT * FROM {".$tablename."}", array(), MUST_EXIST);
1018             $this->fail("Exception expected");
1019         } catch (dml_multiple_records_exception $e) {
1020             $this->assertTrue(true);
1021         }
1022     }
1024     public function test_get_field() {
1025         $DB = $this->tdb;
1026         $dbman = $DB->get_manager();
1028         $table = $this->get_test_table();
1029         $tablename = $table->getName();
1031         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1032         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1033         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1034         $dbman->create_table($table);
1035         $this->tables[$tablename] = $table;
1037         $DB->insert_record($tablename, array('course' => 3));
1039         $this->assertTrue($course = $DB->get_field($tablename, 'course', array('id' => 1)));
1040         $this->assertEqual(3, $course);
1042         // Add one get_field() example where the field being get is also one condition
1043         // to check we haven't problem with any type of param (specially NAMED ones)
1044         $DB->get_field($tablename, 'course', array('course' => 3));
1045         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('course' => 3)));
1046     }
1048     public function test_get_field_select() {
1049         $DB = $this->tdb;
1050         $dbman = $DB->get_manager();
1052         $table = $this->get_test_table();
1053         $tablename = $table->getName();
1055         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1056         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1057         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1058         $dbman->create_table($table);
1059         $this->tables[$tablename] = $table;
1061         $DB->insert_record($tablename, array('course' => 3));
1063         $this->assertTrue($course = $DB->get_field_select($tablename, 'course', "id = ?", array(1)));
1064         $this->assertEqual(3, $course);
1066     }
1068     public function test_get_field_sql() {
1069         $DB = $this->tdb;
1070         $dbman = $DB->get_manager();
1072         $table = $this->get_test_table();
1073         $tablename = $table->getName();
1075         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1076         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1077         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1078         $dbman->create_table($table);
1079         $this->tables[$tablename] = $table;
1081         $DB->insert_record($tablename, array('course' => 3));
1083         $this->assertTrue($course = $DB->get_field_sql("SELECT course FROM {".$tablename."} WHERE id = ?", array(1)));
1084         $this->assertEqual(3, $course);
1086     }
1088     public function test_get_fieldset_select() {
1089         $DB = $this->tdb;
1090         $dbman = $DB->get_manager();
1092         $table = $this->get_test_table();
1093         $tablename = $table->getName();
1095         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1096         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1097         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1098         $dbman->create_table($table);
1099         $this->tables[$tablename] = $table;
1101         $DB->insert_record($tablename, array('course' => 1));
1102         $DB->insert_record($tablename, array('course' => 3));
1103         $DB->insert_record($tablename, array('course' => 2));
1104         $DB->insert_record($tablename, array('course' => 6));
1106         $this->assertTrue($fieldset = $DB->get_fieldset_select($tablename, 'course', "course > ?", array(1)));
1108         $this->assertEqual(3, count($fieldset));
1109         $this->assertEqual(3, $fieldset[0]);
1110         $this->assertEqual(2, $fieldset[1]);
1111         $this->assertEqual(6, $fieldset[2]);
1113     }
1115     public function test_get_fieldset_sql() {
1116         $DB = $this->tdb;
1117         $dbman = $DB->get_manager();
1119         $table = $this->get_test_table();
1120         $tablename = $table->getName();
1122         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1123         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1124         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1125         $dbman->create_table($table);
1126         $this->tables[$tablename] = $table;
1128         $DB->insert_record($tablename, array('course' => 1));
1129         $DB->insert_record($tablename, array('course' => 3));
1130         $DB->insert_record($tablename, array('course' => 2));
1131         $DB->insert_record($tablename, array('course' => 6));
1133         $this->assertTrue($fieldset = $DB->get_fieldset_sql("SELECT * FROM {".$tablename."} WHERE course > ?", array(1)));
1135         $this->assertEqual(3, count($fieldset));
1136         $this->assertEqual(2, $fieldset[0]);
1137         $this->assertEqual(3, $fieldset[1]);
1138         $this->assertEqual(4, $fieldset[2]);
1139     }
1141     public function test_insert_record_raw() {
1142         $DB = $this->tdb;
1143         $dbman = $DB->get_manager();
1145         $table = $this->get_test_table();
1146         $tablename = $table->getName();
1148         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1149         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1150         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1151         $dbman->create_table($table);
1152         $this->tables[$tablename] = $table;
1154         $this->assertTrue($DB->insert_record_raw($tablename, array('course' => 1)));
1155         $this->assertTrue($record = $DB->get_record($tablename, array('course' => 1)));
1156         $this->assertEqual(1, $record->course);
1157     }
1159     public function test_insert_record() {
1161         // All the information in this test is fetched from DB by get_recordset() so we
1162         // have such method properly tested against nulls, empties and friends...
1164         global $CFG;
1166         $DB = $this->tdb;
1167         $dbman = $DB->get_manager();
1169         $table = $this->get_test_table();
1170         $tablename = $table->getName();
1172         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1173         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1174         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
1175         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1176         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1177         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1178         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1179         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1180         $dbman->create_table($table);
1181         $this->tables[$tablename] = $table;
1183         $this->assertTrue($DB->insert_record($tablename, array('course' => 1), false)); // Without returning id
1184         $rs = $DB->get_recordset($tablename, array('course' => 1));
1185         $record = $rs->current();
1186         $rs->close();
1187         $this->assertEqual(1, $record->id);
1188         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
1189         $this->assertEqual(200, $record->onenum);
1190         $this->assertEqual('onestring', $record->onechar);
1191         $this->assertNull($record->onetext);
1192         $this->assertNull($record->onebinary);
1194         // Check nulls are set properly for all types
1195         $record->oneint = null;
1196         $record->onenum = null;
1197         $record->onechar = null;
1198         $record->onetext = null;
1199         $record->onebinary = null;
1200         $recid = $DB->insert_record($tablename, $record);
1201         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1202         $record = $rs->current();
1203         $rs->close();
1204         $this->assertNull($record->oneint);
1205         $this->assertNull($record->onenum);
1206         $this->assertNull($record->onechar);
1207         $this->assertNull($record->onetext);
1208         $this->assertNull($record->onebinary);
1210         // Check zeros are set properly for all types
1211         $record->oneint = 0;
1212         $record->onenum = 0;
1213         $recid = $DB->insert_record($tablename, $record);
1214         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1215         $record = $rs->current();
1216         $rs->close();
1217         $this->assertEqual(0, $record->oneint);
1218         $this->assertEqual(0, $record->onenum);
1220         // Check booleans are set properly for all types
1221         $record->oneint = true; // trues
1222         $record->onenum = true;
1223         $record->onechar = true;
1224         $record->onetext = true;
1225         $recid = $DB->insert_record($tablename, $record);
1226         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1227         $record = $rs->current();
1228         $rs->close();
1229         $this->assertEqual(1, $record->oneint);
1230         $this->assertEqual(1, $record->onenum);
1231         $this->assertEqual(1, $record->onechar);
1232         $this->assertEqual(1, $record->onetext);
1234         $record->oneint = false; // falses
1235         $record->onenum = false;
1236         $record->onechar = false;
1237         $record->onetext = false;
1238         $recid = $DB->insert_record($tablename, $record);
1239         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1240         $record = $rs->current();
1241         $rs->close();
1242         $this->assertEqual(0, $record->oneint);
1243         $this->assertEqual(0, $record->onenum);
1244         $this->assertEqual(0, $record->onechar);
1245         $this->assertEqual(0, $record->onetext);
1247         // Check string data causes exception in numeric types
1248         $record->oneint = 'onestring';
1249         $record->onenum = 0;
1250         try {
1251             $DB->insert_record($tablename, $record);
1252             $this->fail("Expecting an exception, none occurred");
1253         } catch (exception $e) {
1254             $this->assertTrue($e instanceof dml_exception);
1255         }
1256         $record->oneint = 0;
1257         $record->onenum = 'onestring';
1258         try {
1259            $DB->insert_record($tablename, $record);
1260            $this->fail("Expecting an exception, none occurred");
1261         } catch (exception $e) {
1262             $this->assertTrue($e instanceof dml_exception);
1263         }
1265         // Check empty string data is stored as 0 in numeric datatypes
1266         $record->oneint = ''; // empty string
1267         $record->onenum = 0;
1268         $recid = $DB->insert_record($tablename, $record);
1269         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1270         $record = $rs->current();
1271         $rs->close();
1272         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
1274         $record->oneint = 0;
1275         $record->onenum = ''; // empty string
1276         $recid = $DB->insert_record($tablename, $record);
1277         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1278         $record = $rs->current();
1279         $rs->close();
1280         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
1282         // Check empty strings are set properly in string types
1283         $record->oneint = 0;
1284         $record->onenum = 0;
1285         $record->onechar = '';
1286         $record->onetext = '';
1287         $recid = $DB->insert_record($tablename, $record);
1288         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1289         $record = $rs->current();
1290         $rs->close();
1291         $this->assertTrue($record->onechar === '');
1292         $this->assertTrue($record->onetext === '');
1294         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1295         $record->oneint = ((210.10 + 39.92) - 150.02);
1296         $record->onenum = ((210.10 + 39.92) - 150.02);
1297         $recid = $DB->insert_record($tablename, $record);
1298         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1299         $record = $rs->current();
1300         $rs->close();
1301         $this->assertEqual(100, $record->oneint);
1302         $this->assertEqual(100, $record->onenum);
1304         // Check various quotes/backslashes combinations in string types
1305         $teststrings = array(
1306             'backslashes and quotes alone (even): "" \'\' \\\\',
1307             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1308             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1309             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1310         foreach ($teststrings as $teststring) {
1311             $record->onechar = $teststring;
1312             $record->onetext = $teststring;
1313             $recid = $DB->insert_record($tablename, $record);
1314             $rs = $DB->get_recordset($tablename, array('id' => $recid));
1315             $record = $rs->current();
1316             $rs->close();
1317             $this->assertEqual($teststring, $record->onechar);
1318             $this->assertEqual($teststring, $record->onetext);
1319         }
1321         // Check LOBs in text/binary columns
1322         $clob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/clob.txt');
1323         $blob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/randombinary');
1324         $record->onetext = $clob;
1325         $record->onebinary = $blob;
1326         $recid = $DB->insert_record($tablename, $record);
1327         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1328         $record = $rs->current();
1329         $rs->close();
1330         $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
1331         $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
1333         // And "small" LOBs too, just in case
1334         $newclob = substr($clob, 0, 500);
1335         $newblob = substr($blob, 0, 250);
1336         $record->onetext = $newclob;
1337         $record->onebinary = $newblob;
1338         $recid = $DB->insert_record($tablename, $record);
1339         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1340         $record = $rs->current();
1341         $rs->close();
1342         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
1343         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
1344         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
1346         // test data is not modified
1347         $rec = new object();
1348         $rec->id     = -1; // has to be ignored
1349         $rec->course = 3;
1350         $rec->lalala = 'lalal'; // unused
1351         $before = clone($rec);
1352         $DB->insert_record($tablename, $record);
1353         $this->assertEqual($rec, $before);
1354     }
1356     public function test_import_record() {
1357         $DB = $this->tdb;
1358         $dbman = $DB->get_manager();
1360         $table = $this->get_test_table();
1361         $tablename = $table->getName();
1363         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1364         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1365         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1366         $dbman->create_table($table);
1367         $this->tables[$tablename] = $table;
1369         $record = (object)array('id'=>666, 'course'=>10);
1370         $this->assertTrue($DB->import_record($tablename, $record));
1371         $records = $DB->get_records($tablename);
1372         $this->assertEqual(1, count($records));
1373         $this->assertEqual(10, $records[666]->course);
1375         $record = (object)array('id'=>13, 'course'=>2);
1376         $this->assertTrue($DB->import_record($tablename, $record));
1377         $records = $DB->get_records($tablename);
1378         $this->assertEqual(2, $records[13]->course);
1379     }
1381     public function test_update_record_raw() {
1382         $DB = $this->tdb;
1383         $dbman = $DB->get_manager();
1385         $table = $this->get_test_table();
1386         $tablename = $table->getName();
1388         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1389         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1390         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1391         $dbman->create_table($table);
1392         $this->tables[$tablename] = $table;
1394         $DB->insert_record($tablename, array('course' => 1));
1395         $record = $DB->get_record($tablename, array('course' => 1));
1396         $record->course = 2;
1397         $this->assertTrue($DB->update_record_raw($tablename, $record));
1398         $this->assertFalse($record = $DB->get_record($tablename, array('course' => 1)));
1399         $this->assertTrue($record = $DB->get_record($tablename, array('course' => 2)));
1400     }
1402     public function test_update_record() {
1404         // All the information in this test is fetched from DB by get_record() so we
1405         // have such method properly tested against nulls, empties and friends...
1407         global $CFG;
1409         $DB = $this->tdb;
1410         $dbman = $DB->get_manager();
1412         $table = $this->get_test_table();
1413         $tablename = $table->getName();
1415         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1416         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1417         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
1418         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1419         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1420         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1421         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1422         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1423         $dbman->create_table($table);
1424         $this->tables[$tablename] = $table;
1426         $DB->insert_record($tablename, array('course' => 1));
1427         $record = $DB->get_record($tablename, array('course' => 1));
1428         $record->course = 2;
1430         $this->assertTrue($DB->update_record($tablename, $record));
1431         $this->assertFalse($record = $DB->get_record($tablename, array('course' => 1)));
1432         $this->assertTrue($record = $DB->get_record($tablename, array('course' => 2)));
1433         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
1434         $this->assertEqual(200, $record->onenum);
1435         $this->assertEqual('onestring', $record->onechar);
1436         $this->assertNull($record->onetext);
1437         $this->assertNull($record->onebinary);
1439         // Check nulls are set properly for all types
1440         $record->oneint = null;
1441         $record->onenum = null;
1442         $record->onechar = null;
1443         $record->onetext = null;
1444         $record->onebinary = null;
1445         $DB->update_record($tablename, $record);
1446         $record = $DB->get_record($tablename, array('course' => 2));
1447         $this->assertNull($record->oneint);
1448         $this->assertNull($record->onenum);
1449         $this->assertNull($record->onechar);
1450         $this->assertNull($record->onetext);
1451         $this->assertNull($record->onebinary);
1453         // Check zeros are set properly for all types
1454         $record->oneint = 0;
1455         $record->onenum = 0;
1456         $DB->update_record($tablename, $record);
1457         $record = $DB->get_record($tablename, array('course' => 2));
1458         $this->assertEqual(0, $record->oneint);
1459         $this->assertEqual(0, $record->onenum);
1461         // Check booleans are set properly for all types
1462         $record->oneint = true; // trues
1463         $record->onenum = true;
1464         $record->onechar = true;
1465         $record->onetext = true;
1466         $DB->update_record($tablename, $record);
1467         $record = $DB->get_record($tablename, array('course' => 2));
1468         $this->assertEqual(1, $record->oneint);
1469         $this->assertEqual(1, $record->onenum);
1470         $this->assertEqual(1, $record->onechar);
1471         $this->assertEqual(1, $record->onetext);
1473         $record->oneint = false; // falses
1474         $record->onenum = false;
1475         $record->onechar = false;
1476         $record->onetext = false;
1477         $DB->update_record($tablename, $record);
1478         $record = $DB->get_record($tablename, array('course' => 2));
1479         $this->assertEqual(0, $record->oneint);
1480         $this->assertEqual(0, $record->onenum);
1481         $this->assertEqual(0, $record->onechar);
1482         $this->assertEqual(0, $record->onetext);
1484         // Check string data causes exception in numeric types
1485         $record->oneint = 'onestring';
1486         $record->onenum = 0;
1487         try {
1488             $DB->update_record($tablename, $record);
1489             $this->fail("Expecting an exception, none occurred");
1490         } catch (exception $e) {
1491             $this->assertTrue($e instanceof dml_exception);
1492         }
1493         $record->oneint = 0;
1494         $record->onenum = 'onestring';
1495         try {
1496             $DB->update_record($tablename, $record);
1497             $this->fail("Expecting an exception, none occurred");
1498         } catch (exception $e) {
1499             $this->assertTrue($e instanceof dml_exception);
1500         }
1502         // Check empty string data is stored as 0 in numeric datatypes
1503         $record->oneint = ''; // empty string
1504         $record->onenum = 0;
1505         $DB->update_record($tablename, $record);
1506         $record = $DB->get_record($tablename, array('course' => 2));
1507         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
1509         $record->oneint = 0;
1510         $record->onenum = ''; // empty string
1511         $DB->update_record($tablename, $record);
1512         $record = $DB->get_record($tablename, array('course' => 2));
1513         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
1515         // Check empty strings are set properly in string types
1516         $record->oneint = 0;
1517         $record->onenum = 0;
1518         $record->onechar = '';
1519         $record->onetext = '';
1520         $DB->update_record($tablename, $record);
1521         $record = $DB->get_record($tablename, array('course' => 2));
1522         $this->assertTrue($record->onechar === '');
1523         $this->assertTrue($record->onetext === '');
1525         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1526         $record->oneint = ((210.10 + 39.92) - 150.02);
1527         $record->onenum = ((210.10 + 39.92) - 150.02);
1528         $DB->update_record($tablename, $record);
1529         $record = $DB->get_record($tablename, array('course' => 2));
1530         $this->assertEqual(100, $record->oneint);
1531         $this->assertEqual(100, $record->onenum);
1533         // Check various quotes/backslashes combinations in string types
1534         $teststrings = array(
1535             'backslashes and quotes alone (even): "" \'\' \\\\',
1536             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1537             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1538             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1539         foreach ($teststrings as $teststring) {
1540             $record->onechar = $teststring;
1541             $record->onetext = $teststring;
1542             $DB->update_record($tablename, $record);
1543             $record = $DB->get_record($tablename, array('course' => 2));
1544             $this->assertEqual($teststring, $record->onechar);
1545             $this->assertEqual($teststring, $record->onetext);
1546         }
1548         // Check LOBs in text/binary columns
1549         $clob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/clob.txt');
1550         $blob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/randombinary');
1551         $record->onetext = $clob;
1552         $record->onebinary = $blob;
1553         $DB->update_record($tablename, $record);
1554         $record = $DB->get_record($tablename, array('course' => 2));
1555         $this->assertEqual($clob, $record->onetext, 'Test CLOB update (full contents output disabled)');
1556         $this->assertEqual($blob, $record->onebinary, 'Test BLOB update (full contents output disabled)');
1558         // And "small" LOBs too, just in case
1559         $newclob = substr($clob, 0, 500);
1560         $newblob = substr($blob, 0, 250);
1561         $record->onetext = $newclob;
1562         $record->onebinary = $newblob;
1563         $DB->update_record($tablename, $record);
1564         $record = $DB->get_record($tablename, array('course' => 2));
1565         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB update (full contents output disabled)');
1566         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB update (full contents output disabled)');
1567     }
1569     public function test_set_field() {
1570         $DB = $this->tdb;
1571         $dbman = $DB->get_manager();
1573         $table = $this->get_test_table();
1574         $tablename = $table->getName();
1576         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1577         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1578         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1579         $dbman->create_table($table);
1580         $this->tables[$tablename] = $table;
1582         $DB->insert_record($tablename, array('course' => 1));
1584         $this->assertTrue($DB->set_field($tablename, 'course', 2, array('id' => 1)));
1585         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => 1)));
1587         // Add one set_field() example where the field being set is also one condition
1588         // to check we haven't problem with any type of param (specially NAMED ones)
1589         $DB->set_field($tablename, 'course', '1', array('course' => 2));
1590         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => 1)));
1592         // Note: All the nulls, booleans, empties, quoted and backslashes tests
1593         // go to set_field_select() because set_field() is just one wrapper over it
1594     }
1596     public function test_set_field_select() {
1598         // All the information in this test is fetched from DB by get_field() so we
1599         // have such method properly tested against nulls, empties and friends...
1601         global $CFG;
1603         $DB = $this->tdb;
1604         $dbman = $DB->get_manager();
1606         $table = $this->get_test_table();
1607         $tablename = $table->getName();
1609         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1610         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1611         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null);
1612         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null);
1613         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
1614         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1615         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1616         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1617         $dbman->create_table($table);
1618         $this->tables[$tablename] = $table;
1620         $DB->insert_record($tablename, array('course' => 1));
1622         $this->assertTrue($DB->set_field_select($tablename, 'course', 2, 'id = ?', array(1)));
1623         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => 1)));
1625         // Check nulls are set properly for all types
1626         $DB->set_field_select($tablename, 'oneint', null, 'id = ?', array(1)); // trues
1627         $DB->set_field_select($tablename, 'onenum', null, 'id = ?', array(1));
1628         $DB->set_field_select($tablename, 'onechar', null, 'id = ?', array(1));
1629         $DB->set_field_select($tablename, 'onetext', null, 'id = ?', array(1));
1630         $DB->set_field_select($tablename, 'onebinary', null, 'id = ?', array(1));
1631         $this->assertNull($DB->get_field($tablename, 'oneint', array('id' => 1)));
1632         $this->assertNull($DB->get_field($tablename, 'onenum', array('id' => 1)));
1633         $this->assertNull($DB->get_field($tablename, 'onechar', array('id' => 1)));
1634         $this->assertNull($DB->get_field($tablename, 'onetext', array('id' => 1)));
1635         $this->assertNull($DB->get_field($tablename, 'onebinary', array('id' => 1)));
1637         // Check zeros are set properly for all types
1638         $DB->set_field_select($tablename, 'oneint', 0, 'id = ?', array(1));
1639         $DB->set_field_select($tablename, 'onenum', 0, 'id = ?', array(1));
1640         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
1641         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
1643         // Check booleans are set properly for all types
1644         $DB->set_field_select($tablename, 'oneint', true, 'id = ?', array(1)); // trues
1645         $DB->set_field_select($tablename, 'onenum', true, 'id = ?', array(1));
1646         $DB->set_field_select($tablename, 'onechar', true, 'id = ?', array(1));
1647         $DB->set_field_select($tablename, 'onetext', true, 'id = ?', array(1));
1648         $this->assertEqual(1, $DB->get_field($tablename, 'oneint', array('id' => 1)));
1649         $this->assertEqual(1, $DB->get_field($tablename, 'onenum', array('id' => 1)));
1650         $this->assertEqual(1, $DB->get_field($tablename, 'onechar', array('id' => 1)));
1651         $this->assertEqual(1, $DB->get_field($tablename, 'onetext', array('id' => 1)));
1653         $DB->set_field_select($tablename, 'oneint', false, 'id = ?', array(1)); // falses
1654         $DB->set_field_select($tablename, 'onenum', false, 'id = ?', array(1));
1655         $DB->set_field_select($tablename, 'onechar', false, 'id = ?', array(1));
1656         $DB->set_field_select($tablename, 'onetext', false, 'id = ?', array(1));
1657         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
1658         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
1659         $this->assertEqual(0, $DB->get_field($tablename, 'onechar', array('id' => 1)));
1660         $this->assertEqual(0, $DB->get_field($tablename, 'onetext', array('id' => 1)));
1662         // Check string data causes exception in numeric types
1663         try {
1664             $DB->set_field_select($tablename, 'oneint', 'onestring', 'id = ?', array(1));
1665             $this->fail("Expecting an exception, none occurred");
1666         } catch (exception $e) {
1667             $this->assertTrue($e instanceof dml_exception);
1668         }
1669         try {
1670             $DB->set_field_select($tablename, 'onenum', 'onestring', 'id = ?', array(1));
1671             $this->fail("Expecting an exception, none occurred");
1672         } catch (exception $e) {
1673             $this->assertTrue($e instanceof dml_exception);
1674         }
1676         // Check empty string data is stored as 0 in numeric datatypes
1677         $DB->set_field_select($tablename, 'oneint', '', 'id = ?', array(1));
1678         $field = $DB->get_field($tablename, 'oneint', array('id' => 1));
1679         $this->assertTrue(is_numeric($field) && $field == 0);
1681         $DB->set_field_select($tablename, 'onenum', '', 'id = ?', array(1));
1682         $field = $DB->get_field($tablename, 'onenum', array('id' => 1));
1683         $this->assertTrue(is_numeric($field) && $field == 0);
1685         // Check empty strings are set properly in string types
1686         $DB->set_field_select($tablename, 'onechar', '', 'id = ?', array(1));
1687         $DB->set_field_select($tablename, 'onetext', '', 'id = ?', array(1));
1688         $this->assertTrue($DB->get_field($tablename, 'onechar', array('id' => 1)) === '');
1689         $this->assertTrue($DB->get_field($tablename, 'onetext', array('id' => 1)) === '');
1691         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1692         $DB->set_field_select($tablename, 'oneint', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
1693         $DB->set_field_select($tablename, 'onenum', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
1694         $this->assertEqual(100, $DB->get_field($tablename, 'oneint', array('id' => 1)));
1695         $this->assertEqual(100, $DB->get_field($tablename, 'onenum', array('id' => 1)));
1697         // Check various quotes/backslashes combinations in string types
1698         $teststrings = array(
1699             'backslashes and quotes alone (even): "" \'\' \\\\',
1700             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1701             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1702             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1703         foreach ($teststrings as $teststring) {
1704             $DB->set_field_select($tablename, 'onechar', $teststring, 'id = ?', array(1));
1705             $DB->set_field_select($tablename, 'onetext', $teststring, 'id = ?', array(1));
1706             $this->assertEqual($teststring, $DB->get_field($tablename, 'onechar', array('id' => 1)));
1707             $this->assertEqual($teststring, $DB->get_field($tablename, 'onetext', array('id' => 1)));
1708         }
1710         // Check LOBs in text/binary columns
1711         $clob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/clob.txt');
1712         $blob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/randombinary');
1713         $DB->set_field_select($tablename, 'onetext', $clob, 'id = ?', array(1));
1714         $DB->set_field_select($tablename, 'onebinary', $blob, 'id = ?', array(1));
1715         $this->assertEqual($clob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test CLOB set_field (full contents output disabled)');
1716         $this->assertEqual($blob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test BLOB set_field (full contents output disabled)');
1718         // And "small" LOBs too, just in case
1719         $newclob = substr($clob, 0, 500);
1720         $newblob = substr($blob, 0, 250);
1721         $DB->set_field_select($tablename, 'onetext', $newclob, 'id = ?', array(1));
1722         $DB->set_field_select($tablename, 'onebinary', $newblob, 'id = ?', array(1));
1723         $this->assertEqual($newclob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test "small" CLOB set_field (full contents output disabled)');
1724         $this->assertEqual($newblob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test "small" BLOB set_field (full contents output disabled)');
1725     }
1727     public function test_count_records() {
1728         $DB = $this->tdb;
1730         $dbman = $DB->get_manager();
1732         $table = $this->get_test_table();
1733         $tablename = $table->getName();
1735         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1736         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1737         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1738         $dbman->create_table($table);
1739         $this->tables[$tablename] = $table;
1741         $this->assertEqual(0, $DB->count_records($tablename));
1743         $DB->insert_record($tablename, array('course' => 3));
1744         $DB->insert_record($tablename, array('course' => 4));
1745         $DB->insert_record($tablename, array('course' => 5));
1747         $this->assertEqual(3, $DB->count_records($tablename));
1748     }
1750     public function test_count_records_select() {
1751         $DB = $this->tdb;
1753         $dbman = $DB->get_manager();
1755         $table = $this->get_test_table();
1756         $tablename = $table->getName();
1758         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1759         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1760         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1761         $dbman->create_table($table);
1762         $this->tables[$tablename] = $table;
1764         $this->assertEqual(0, $DB->count_records($tablename));
1766         $DB->insert_record($tablename, array('course' => 3));
1767         $DB->insert_record($tablename, array('course' => 4));
1768         $DB->insert_record($tablename, array('course' => 5));
1770         $this->assertEqual(2, $DB->count_records_select($tablename, 'course > ?', array(3)));
1771     }
1773     public function test_count_records_sql() {
1774         $DB = $this->tdb;
1775         $dbman = $DB->get_manager();
1777         $table = $this->get_test_table();
1778         $tablename = $table->getName();
1780         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1781         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1782         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1783         $dbman->create_table($table);
1784         $this->tables[$tablename] = $table;
1786         $this->assertEqual(0, $DB->count_records($tablename));
1788         $DB->insert_record($tablename, array('course' => 3));
1789         $DB->insert_record($tablename, array('course' => 4));
1790         $DB->insert_record($tablename, array('course' => 5));
1792         $this->assertEqual(2, $DB->count_records_sql("SELECT COUNT(*) FROM {".$tablename."} WHERE course > ?", array(3)));
1793     }
1795     public function test_record_exists() {
1796         $DB = $this->tdb;
1797         $dbman = $DB->get_manager();
1799         $table = $this->get_test_table();
1800         $tablename = $table->getName();
1802         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1803         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1804         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1805         $dbman->create_table($table);
1806         $this->tables[$tablename] = $table;
1808         $this->assertEqual(0, $DB->count_records($tablename));
1810         $this->assertFalse($DB->record_exists($tablename, array('course' => 3)));
1811         $DB->insert_record($tablename, array('course' => 3));
1813         $this->assertTrue($DB->record_exists($tablename, array('course' => 3)));
1815     }
1817     public function test_record_exists_select() {
1818         $DB = $this->tdb;
1819         $dbman = $DB->get_manager();
1821         $table = $this->get_test_table();
1822         $tablename = $table->getName();
1824         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1825         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1826         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1827         $dbman->create_table($table);
1828         $this->tables[$tablename] = $table;
1830         $this->assertEqual(0, $DB->count_records($tablename));
1832         $this->assertFalse($DB->record_exists_select($tablename, "course = ?", array(3)));
1833         $DB->insert_record($tablename, array('course' => 3));
1835         $this->assertTrue($DB->record_exists_select($tablename, "course = ?", array(3)));
1836     }
1838     public function test_record_exists_sql() {
1839         $DB = $this->tdb;
1840         $dbman = $DB->get_manager();
1842         $table = $this->get_test_table();
1843         $tablename = $table->getName();
1845         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1846         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1847         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1848         $dbman->create_table($table);
1849         $this->tables[$tablename] = $table;
1851         $this->assertEqual(0, $DB->count_records($tablename));
1853         $this->assertFalse($DB->record_exists_sql("SELECT * FROM {".$tablename."} WHERE course = ?", array(3)));
1854         $DB->insert_record($tablename, array('course' => 3));
1856         $this->assertTrue($DB->record_exists_sql("SELECT * FROM {".$tablename."} WHERE course = ?", array(3)));
1857     }
1859     public function test_delete_records() {
1860         $DB = $this->tdb;
1861         $dbman = $DB->get_manager();
1863         $table = $this->get_test_table();
1864         $tablename = $table->getName();
1866         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1867         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1868         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1869         $dbman->create_table($table);
1870         $this->tables[$tablename] = $table;
1872         $DB->insert_record($tablename, array('course' => 3));
1873         $DB->insert_record($tablename, array('course' => 2));
1874         $DB->insert_record($tablename, array('course' => 2));
1876         // Delete all records
1877         $this->assertTrue($DB->delete_records($tablename));
1878         $this->assertEqual(0, $DB->count_records($tablename));
1880         // Delete subset of records
1881         $DB->insert_record($tablename, array('course' => 3));
1882         $DB->insert_record($tablename, array('course' => 2));
1883         $DB->insert_record($tablename, array('course' => 2));
1885         $this->assertTrue($DB->delete_records($tablename, array('course' => 2)));
1886         $this->assertEqual(1, $DB->count_records($tablename));
1887     }
1889     public function test_delete_records_select() {
1890         $DB = $this->tdb;
1891         $dbman = $DB->get_manager();
1893         $table = $this->get_test_table();
1894         $tablename = $table->getName();
1896         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1897         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1898         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1899         $dbman->create_table($table);
1900         $this->tables[$tablename] = $table;
1902         $DB->insert_record($tablename, array('course' => 3));
1903         $DB->insert_record($tablename, array('course' => 2));
1904         $DB->insert_record($tablename, array('course' => 2));
1906         $this->assertTrue($DB->delete_records_select($tablename, 'course = ?', array(2)));
1907         $this->assertEqual(1, $DB->count_records($tablename));
1908     }
1910     public function test_delete_records_list() {
1911         $DB = $this->tdb;
1912         $dbman = $DB->get_manager();
1914         $table = $this->get_test_table();
1915         $tablename = $table->getName();
1917         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1918         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1919         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1920         $dbman->create_table($table);
1921         $this->tables[$tablename] = $table;
1923         $DB->insert_record($tablename, array('course' => 1));
1924         $DB->insert_record($tablename, array('course' => 2));
1925         $DB->insert_record($tablename, array('course' => 3));
1927         $this->assertTrue($DB->delete_records_list($tablename, 'course', array(2, 3)));
1928         $this->assertEqual(1, $DB->count_records($tablename));
1930         $this->assertTrue($DB->delete_records_list($tablename, 'course', array())); /// Must delete 0 rows without conditions. MDL-17645
1931         $this->assertEqual(1, $DB->count_records($tablename));
1932     }
1934     function test_sql_null_from_clause() {
1935         $DB = $this->tdb;
1936         $sql = "SELECT 1 AS id ".$DB->sql_null_from_clause();
1937         $this->assertEqual($DB->get_field_sql($sql), 1);
1938     }
1940     function test_sql_bitand() {
1941         $DB = $this->tdb;
1942         $sql = "SELECT ".$DB->sql_bitand(10, 3)." AS res ".$DB->sql_null_from_clause();
1943         $this->assertEqual($DB->get_field_sql($sql), 2);
1944     }
1946     function test_sql_bitnot() {
1947         $DB = $this->tdb;
1949         $not = $DB->sql_bitnot(2);
1950         $notlimited = $DB->sql_bitand($not, 7); // might be positive or negative number which can not fit into PHP INT!
1952         $sql = "SELECT $notlimited AS res ".$DB->sql_null_from_clause();
1953         $this->assertEqual($DB->get_field_sql($sql), 5);
1954     }
1956     function test_sql_bitor() {
1957         $DB = $this->tdb;
1958         $sql = "SELECT ".$DB->sql_bitor(10, 3)." AS res ".$DB->sql_null_from_clause();
1959         $this->assertEqual($DB->get_field_sql($sql), 11);
1960     }
1962     function test_sql_bitxor() {
1963         $DB = $this->tdb;
1964         $sql = "SELECT ".$DB->sql_bitxor(10, 3)." AS res ".$DB->sql_null_from_clause();
1965         $this->assertEqual($DB->get_field_sql($sql), 9);
1966     }
1968     function test_sql_modulo() {
1969         $DB = $this->tdb;
1970         $sql = "SELECT ".$DB->sql_modulo(10, 7)." AS res ".$DB->sql_null_from_clause();
1971         $this->assertEqual($DB->get_field_sql($sql), 3);
1972     }
1974     function test_sql_ceil() {
1975         $DB = $this->tdb;
1976         $sql = "SELECT ".$DB->sql_ceil(665.666)." AS res ".$DB->sql_null_from_clause();
1977         $this->assertEqual($DB->get_field_sql($sql), 666);
1978     }
1980     function test_cast_char2int() {
1981         $DB = $this->tdb;
1982         $dbman = $DB->get_manager();
1984         $table1 = $this->get_test_table("testtable1");
1985         $tablename1 = $table1->getName();
1987         $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1988         $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
1989         $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1990         $dbman->create_table($table1);
1991         $this->tables[$tablename1] = $table1;
1993         $DB->insert_record($tablename1, array('name'=>'100'));
1995         $table2 = $this->get_test_table("testtable2");
1996         $tablename2 = $table2->getName();
1997         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1998         $table2->add_field('res', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1999         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2000         $dbman->create_table($table2);
2001         $this->tables[$table2->getName()] = $table2;
2003         $DB->insert_record($tablename2, array('res'=>100));
2005         try {
2006             $sql = "SELECT * FROM {".$tablename1."} t1, {".$tablename2."} t2 WHERE ".$DB->sql_cast_char2int("t1.name")." = t2.res ";
2007             $records = $DB->get_records_sql($sql);
2008             $this->assertEqual(count($records), 1);
2009         } catch (dml_exception $e) {
2010             $this->fail("No exception expected");
2011         }
2012     }
2014     function test_cast_char2real() {
2015         $DB = $this->tdb;
2016         $dbman = $DB->get_manager();
2018         $table = $this->get_test_table();
2019         $tablename = $table->getName();
2021         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2022         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2023         $table->add_field('res', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null);
2024         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2025         $dbman->create_table($table);
2026         $this->tables[$tablename] = $table;
2028         $DB->insert_record($tablename, array('name'=>'10.10', 'res'=>5.1));
2029         $DB->insert_record($tablename, array('name'=>'1.10', 'res'=>666));
2030         $DB->insert_record($tablename, array('name'=>'11.10', 'res'=>0.1));
2032         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_cast_char2real('name')." > res";
2033         $records = $DB->get_records_sql($sql);
2034         $this->assertEqual(count($records), 2);
2035     }
2037     function sql_compare_text() {
2038         $DB = $this->tdb;
2039         $dbman = $DB->get_manager();
2041         $table = $this->get_test_table();
2042         $tablename = $table->getName();
2044         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2045         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2046         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2047         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2048         $dbman->create_table($table);
2049         $this->tables[$tablename] = $table;
2051         $DB->insert_record($tablename, array('name'=>'abcd',   'description'=>'abcd'));
2052         $DB->insert_record($tablename, array('name'=>'abcdef', 'description'=>'bbcdef'));
2053         $DB->insert_record($tablename, array('name'=>'aaaabb', 'description'=>'aaaacccccccccccccccccc'));
2055         $sql = "SELECT * FROM {".$tablename."} WHERE name = ".$DB->sql_compare_text('description');
2056         $records = $DB->get_records_sql($sql);
2057         $this->assertEqual(count($records), 1);
2059         $sql = "SELECT * FROM {".$tablename."} WHERE name = ".$DB->sql_compare_text('description', 4);
2060         $records = $DB->get_records_sql($sql);
2061         $this->assertEqual(count($records), 2);
2062     }
2065     function test_sql_binary_equal() {
2066         $DB = $this->tdb;
2067         $dbman = $DB->get_manager();
2069         $table = $this->get_test_table();
2070         $tablename = $table->getName();
2072         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2073         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2074         $table->add_field('descr', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2075         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2076         $dbman->create_table($table);
2077         $this->tables[$tablename] = $table;
2079         $DB->insert_record($tablename, array('name'=>'skodak', 'descr'=>'Skodak'));
2080         $DB->insert_record($tablename, array('name'=>'skodák', 'descr'=>'skodák'));
2081         $DB->insert_record($tablename, array('name'=>'Skodak', 'descr'=>'Skodák'));
2082         $DB->insert_record($tablename, array('name'=>'?ko?ák', 'descr'=>'?ko?ák'));
2083         $DB->insert_record($tablename, array('name'=>'skodäk', 'descr'=>'skodak'));
2085         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_binary_equal('name', '?');
2086         $records = $DB->get_records_sql($sql, array("skodak"));
2087         $this->assertEqual(count($records), 1);
2089         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_binary_equal('name', '?');
2090         $records = $DB->get_records_sql($sql, array("?ko?ák"));
2091         $this->assertEqual(count($records), 1);
2093         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_binary_equal('name', 'descr');
2094         $records = $DB->get_records_sql($sql, array());
2095         $this->assertEqual(count($records), 1);
2097         // get_records() is supposed to use binary comparison too
2098         $records = $DB->get_records($tablename, array('name'=>"skodak"));
2099         $this->assertEqual(count($records), 1);
2100         $records = $DB->get_records($tablename, array('name'=>"?ko?ák"));
2101         $this->assertEqual(count($records), 1);
2103         $bool = $DB->record_exists($tablename, array('name'=>"skodak"));
2104         $this->assertTrue($bool);
2105         $bool = $DB->record_exists($tablename, array('name'=>"skodAk"));
2106         $this->assertFalse($bool);
2107     }
2109     function test_sql_like() {
2110         $DB = $this->tdb;
2111         $dbman = $DB->get_manager();
2113         $table = $this->get_test_table();
2114         $tablename = $table->getName();
2116         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2117         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2118         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2119         $dbman->create_table($table);
2120         $this->tables[$tablename] = $table;
2122         $DB->insert_record($tablename, array('name'=>'SuperDuperRecord'));
2123         $DB->insert_record($tablename, array('name'=>'Nodupor'));
2124         $DB->insert_record($tablename, array('name'=>'ouch'));
2125         $DB->insert_record($tablename, array('name'=>'ouc_'));
2126         $DB->insert_record($tablename, array('name'=>'ouc%'));
2127         $DB->insert_record($tablename, array('name'=>'aui'));
2128         $DB->insert_record($tablename, array('name'=>'aüi'));
2129         $DB->insert_record($tablename, array('name'=>'aÜi'));
2131         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_like('name', '?', false);
2132         $records = $DB->get_records_sql($sql, array("%dup_r%"));
2133         $this->assertEqual(count($records), 2);
2135         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_like('name', '?', true);
2136         $records = $DB->get_records_sql($sql, array("%dup%"));
2137         $this->assertEqual(count($records), 1);
2139         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_like('name', '?'); // defaults
2140         $records = $DB->get_records_sql($sql, array("%dup%"));
2141         $this->assertEqual(count($records), 1);
2143         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_like('name', '?', true);
2144         $records = $DB->get_records_sql($sql, array("ouc\\_"));
2145         $this->assertEqual(count($records), 1);
2147         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_like('name', '?', true, true, '|');
2148         $records = $DB->get_records_sql($sql, array($DB->sql_like_escape("ouc%", '|')));
2149         $this->assertEqual(count($records), 1);
2151         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_like('name', '?', true, true);
2152         $records = $DB->get_records_sql($sql, array('aui'));
2153         $this->assertEqual(count($records), 1);
2155         // we do not require accent insensitivness yet, just make sure it does not throw errors
2156         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_like('name', '?', true, false);
2157         $records = $DB->get_records_sql($sql, array('aui'));
2158         $this->assertEqual(count($records), 2, 'Accent insensitive LIKE searches may not be supported in all database backends, ignore this problem for now.');
2159         $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_like('name', '?', false, false);
2160         $records = $DB->get_records_sql($sql, array('aui'));
2161         $this->assertEqual(count($records), 3, 'Accent insensitive LIKE searches may not be supported in all database backends, ignore this problem for now.');
2162     }
2164     function test_sql_ilike() {
2165         $DB = $this->tdb;
2166         $dbman = $DB->get_manager();
2168         $table = $this->get_test_table();
2169         $tablename = $table->getName();
2171         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2172         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2173         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2174         $dbman->create_table($table);
2175         $this->tables[$tablename] = $table;
2177         $DB->insert_record($tablename, array('name'=>'SuperDuperRecord'));
2178         $DB->insert_record($tablename, array('name'=>'NoDupor'));
2179         $DB->insert_record($tablename, array('name'=>'ouch'));
2181         $sql = "SELECT * FROM {".$tablename."} WHERE name ".$DB->sql_ilike()." ?";
2182         $params = array("%dup_r%");
2183         $records = $DB->get_records_sql($sql, $params);
2184         $this->assertEqual(count($records), 2, 'DB->sql_ilike() is deprecated, ignore this problem.');
2185     }
2187     function test_sql_concat() {
2188         $DB = $this->tdb;
2189         $dbman = $DB->get_manager();
2191         /// Testing all sort of values
2192         $sql = "SELECT ".$DB->sql_concat("?", "?", "?")." AS fullname ". $DB->sql_null_from_clause();
2193         // string, some unicode chars
2194         $params = array('name', 'áéíóú', 'name3');
2195         $this->assertEqual('nameáéíóúname3', $DB->get_field_sql($sql, $params));
2196         // string, spaces and numbers
2197         $params = array('name', '  ', 12345);
2198         $this->assertEqual('name  12345', $DB->get_field_sql($sql, $params));
2199         // float, empty and strings
2200         $params = array(123.45, '', 'test');
2201         $this->assertEqual('123.45test', $DB->get_field_sql($sql, $params));
2202         // float, null and strings
2203         $params = array(123.45, null, 'test');
2204         $this->assertNull($DB->get_field_sql($sql, $params), 'ANSI behaviour: Concatenating NULL must return NULL - But in Oracle :-(. [%s]'); // Concatenate NULL with anything result = NULL
2206         /// Testing fieldnames + values
2207         $table = $this->get_test_table();
2208         $tablename = $table->getName();
2210         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2211         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2212         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2213         $dbman->create_table($table);
2214         $this->tables[$tablename] = $table;
2216         $DB->insert_record($tablename, array('description'=>'áéíóú'));
2217         $DB->insert_record($tablename, array('description'=>'dxxx'));
2218         $DB->insert_record($tablename, array('description'=>'bcde'));
2220         $sql = 'SELECT id, ' . $DB->sql_concat('description', "'harcoded'", '?', '?') . ' AS result FROM {' . $tablename . '}';
2221         $records = $DB->get_records_sql($sql, array(123.45, 'test'));
2222         $this->assertEqual(count($records), 3);
2223         $this->assertEqual($records[1]->result, 'áéíóúharcoded123.45test');
2224     }
2226     function test_concat_join() {
2227         $DB = $this->tdb;
2228         $sql = "SELECT ".$DB->sql_concat_join("' '", array("?", "?", "?"))." AS fullname ".$DB->sql_null_from_clause();
2229         $params = array("name", "name2", "name3");
2230         $result = $DB->get_field_sql($sql, $params);
2231         $this->assertEqual("name name2 name3", $result);
2232     }
2234     function test_sql_fullname() {
2235         $DB = $this->tdb;
2236         $sql = "SELECT ".$DB->sql_fullname(':first', ':last')." AS fullname ".$DB->sql_null_from_clause();
2237         $params = array('first'=>'Firstname', 'last'=>'Surname');
2238         $this->assertEqual("Firstname Surname", $DB->get_field_sql($sql, $params));
2239     }
2241     function sql_sql_order_by_text() {
2242         $DB = $this->tdb;
2243         $dbman = $DB->get_manager();
2245         $table = $this->get_test_table();
2246         $tablename = $table->getName();
2248         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2249         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2250         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2251         $dbman->create_table($table);
2252         $this->tables[$tablename] = $table;
2254         $DB->insert_record($tablename, array('description'=>'abcd'));
2255         $DB->insert_record($tablename, array('description'=>'dxxx'));
2256         $DB->insert_record($tablename, array('description'=>'bcde'));
2258         $sql = "SELECT * FROM {".$tablename."} ORDER BY ".$DB->sql_order_by_text('description');
2259         $records = $DB->get_records_sql($sql);
2260         $first = array_unshift($records);
2261         $this->assertEqual(1, $first->id);
2262         $second = array_unshift($records);
2263         $this->assertEqual(3, $second->id);
2264         $last = array_unshift($records);
2265         $this->assertEqual(2, $last->id);
2266     }
2268     function test_sql_substring() {
2269         $DB = $this->tdb;
2270         $dbman = $DB->get_manager();
2272         $table = $this->get_test_table();
2273         $tablename = $table->getName();
2275         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2276         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2277         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2278         $dbman->create_table($table);
2279         $this->tables[$tablename] = $table;
2281         $string = 'abcdefghij';
2283         $DB->insert_record($tablename, array('name'=>$string));
2285         $sql = "SELECT id, ".$DB->sql_substr("name", 5)." AS name FROM {".$tablename."}";
2286         $record = $DB->get_record_sql($sql);
2287         $this->assertEqual(substr($string, 5-1), $record->name);
2289         $sql = "SELECT id, ".$DB->sql_substr("name", 5, 2)." AS name FROM {".$tablename."}";
2290         $record = $DB->get_record_sql($sql);
2291         $this->assertEqual(substr($string, 5-1, 2), $record->name);
2293         try {
2294             // silence php warning ;-)
2295             @$DB->sql_substr("name");
2296             $this->fail("Expecting an exception, none occurred");
2297         } catch (Exception $e) {
2298             $this->assertTrue($e instanceof coding_exception);
2299         }
2300     }
2302     function test_sql_length() {
2303         $DB = $this->tdb;
2304         $this->assertEqual($DB->get_field_sql(
2305                 "SELECT ".$DB->sql_length("'aeiou'").$DB->sql_null_from_clause()), 5);
2306         $this->assertEqual($DB->get_field_sql(
2307                 "SELECT ".$DB->sql_length("'áéíóú'").$DB->sql_null_from_clause()), 5);
2308     }
2310     function test_sql_position() {
2311         $DB = $this->tdb;
2312         $this->assertEqual($DB->get_field_sql(
2313                 "SELECT ".$DB->sql_position("'ood'", "'Moodle'").$DB->sql_null_from_clause()), 2);
2314         $this->assertEqual($DB->get_field_sql(
2315                 "SELECT ".$DB->sql_position("'Oracle'", "'Moodle'").$DB->sql_null_from_clause()), 0);
2316     }
2318     function test_sql_empty() {
2319         $DB = $this->tdb;
2320         $dbman = $DB->get_manager();
2322         $table = $this->get_test_table();
2323         $tablename = $table->getName();
2325         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2326         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2327         $table->add_field('namenotnull', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'default value');
2328         $table->add_field('namenotnullnodeflt', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2329         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2330         $dbman->create_table($table);
2331         $this->tables[$tablename] = $table;
2333         $DB->insert_record($tablename, array('name'=>'', 'namenotnull'=>''));
2334         $DB->insert_record($tablename, array('name'=>null));
2335         $DB->insert_record($tablename, array('name'=>'lalala'));
2336         $DB->insert_record($tablename, array('name'=>0));
2338         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE name = '".$DB->sql_empty()."'");
2339         $this->assertEqual(count($records), 1);
2340         $record = reset($records);
2341         $this->assertEqual($record->name, '');
2343         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE namenotnull = '".$DB->sql_empty()."'");
2344         $this->assertEqual(count($records), 1);
2345         $record = reset($records);
2346         $this->assertEqual($record->namenotnull, '');
2348         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE namenotnullnodeflt = '".$DB->sql_empty()."'");
2349         $this->assertEqual(count($records), 4);
2350         $record = reset($records);
2351         $this->assertEqual($record->namenotnullnodeflt, '');
2352     }
2354     function test_sql_isempty() {
2355         $DB = $this->tdb;
2356         $dbman = $DB->get_manager();
2358         $table = $this->get_test_table();
2359         $tablename = $table->getName();
2361         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2362         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2363         $table->add_field('namenull', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2364         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null);
2365         $table->add_field('descriptionnull', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2366         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2367         $dbman->create_table($table);
2368         $this->tables[$tablename] = $table;
2370         $DB->insert_record($tablename, array('name'=>'',   'namenull'=>'',   'description'=>'',   'descriptionnull'=>''));
2371         $DB->insert_record($tablename, array('name'=>'??', 'namenull'=>null, 'description'=>'??', 'descriptionnull'=>null));
2372         $DB->insert_record($tablename, array('name'=>'la', 'namenull'=>'la', 'description'=>'la', 'descriptionnull'=>'lalala'));
2373         $DB->insert_record($tablename, array('name'=>0,    'namenull'=>0,    'description'=>0,    'descriptionnull'=>0));
2375         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isempty($tablename, 'name', false, false));
2376         $this->assertEqual(count($records), 1);
2377         $record = reset($records);
2378         $this->assertEqual($record->name, '');
2380         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isempty($tablename, 'namenull', true, false));
2381         $this->assertEqual(count($records), 1);
2382         $record = reset($records);
2383         $this->assertEqual($record->namenull, '');
2385         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isempty($tablename, 'description', false, true));
2386         $this->assertEqual(count($records), 1);
2387         $record = reset($records);
2388         $this->assertEqual($record->description, '');
2390         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isempty($tablename, 'descriptionnull', true, true));
2391         $this->assertEqual(count($records), 1);
2392         $record = reset($records);
2393         $this->assertEqual($record->descriptionnull, '');
2394     }
2396     function test_sql_isnotempty() {
2397         $DB = $this->tdb;
2398         $dbman = $DB->get_manager();
2400         $table = $this->get_test_table();
2401         $tablename = $table->getName();
2403         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2404         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2405         $table->add_field('namenull', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2406         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null);
2407         $table->add_field('descriptionnull', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2408         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2409         $dbman->create_table($table);
2410         $this->tables[$tablename] = $table;
2412         $DB->insert_record($tablename, array('name'=>'',   'namenull'=>'',   'description'=>'',   'descriptionnull'=>''));
2413         $DB->insert_record($tablename, array('name'=>'??', 'namenull'=>null, 'description'=>'??', 'descriptionnull'=>null));
2414         $DB->insert_record($tablename, array('name'=>'la', 'namenull'=>'la', 'description'=>'la', 'descriptionnull'=>'lalala'));
2415         $DB->insert_record($tablename, array('name'=>0,    'namenull'=>0,    'description'=>0,    'descriptionnull'=>0));
2417         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isnotempty($tablename, 'name', false, false));
2418         $this->assertEqual(count($records), 3);
2419         $record = reset($records);
2420         $this->assertEqual($record->name, '??');
2422         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isnotempty($tablename, 'namenull', true, false));
2423         $this->assertEqual(count($records), 2); // nulls aren't comparable (so they aren't "not empty"). SQL expected behaviour
2424         $record = reset($records);
2425         $this->assertEqual($record->namenull, 'la'); // so 'la' is the first non-empty 'namenull' record
2427         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isnotempty($tablename, 'description', false, true));
2428         $this->assertEqual(count($records), 3);
2429         $record = reset($records);
2430         $this->assertEqual($record->description, '??');
2432         $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isnotempty($tablename, 'descriptionnull', true, true));
2433         $this->assertEqual(count($records), 2); // nulls aren't comparable (so they aren't "not empty"). SQL expected behaviour
2434         $record = reset($records);
2435         $this->assertEqual($record->descriptionnull, 'lalala'); // so 'lalala' is the first non-empty 'descriptionnull' record
2436     }
2438     function test_sql_regex() {
2439         $DB = $this->tdb;
2440         $dbman = $DB->get_manager();
2442         $table = $this->get_test_table();
2443         $tablename = $table->getName();
2445         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2446         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2447         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2448         $dbman->create_table($table);
2449         $this->tables[$tablename] = $table;
2451         $DB->insert_record($tablename, array('name'=>'lalala'));
2452         $DB->insert_record($tablename, array('name'=>'holaaa'));
2453         $DB->insert_record($tablename, array('name'=>'aouch'));
2455         $sql = "SELECT * FROM {".$tablename."} WHERE name ".$DB->sql_regex()." ?";
2456         $params = array('a$');
2457         if ($DB->sql_regex_supported()) {
2458             $records = $DB->get_records_sql($sql, $params);
2459             $this->assertEqual(count($records), 2);
2460         } else {
2461             $this->assertTrue(true, 'Regexp operations not supported. Test skipped');
2462         }
2464         $sql = "SELECT * FROM {".$tablename."} WHERE name ".$DB->sql_regex(false)." ?";
2465         $params = array('.a');
2466         if ($DB->sql_regex_supported()) {
2467             $records = $DB->get_records_sql($sql, $params);
2468             $this->assertEqual(count($records), 1);
2469         } else {
2470             $this->assertTrue(true, 'Regexp operations not supported. Test skipped');
2471         }
2473     }
2475     /**
2476      * Test some more complex SQL syntax which moodle uses and depends on to work
2477      * useful to determine if new database libraries can be supported.
2478      */
2479     public function test_get_records_sql_complicated() {
2480         global $CFG;
2481         $DB = $this->tdb;
2482         $dbman = $DB->get_manager();
2484         $table = $this->get_test_table();
2485         $tablename = $table->getName();
2487         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2488         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2489         $table->add_field('content', XMLDB_TYPE_TEXT, 'big', XMLDB_UNSIGNED, XMLDB_NOTNULL);
2490         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2491         $dbman->create_table($table);
2492         $this->tables[$tablename] = $table;
2494         $DB->insert_record($tablename, array('course' => 3, 'content' => 'hello'));
2495         $DB->insert_record($tablename, array('course' => 3, 'content' => 'world'));
2496         $DB->insert_record($tablename, array('course' => 5, 'content' => 'hello'));
2497         $DB->insert_record($tablename, array('course' => 2, 'content' => 'universe'));
2499         // we have sql like this in moodle, this syntax breaks on older versions of sqlite for example..
2500         $sql = 'SELECT a.id AS id, a.course AS course
2501                 FROM {'.$tablename.'} a
2502                 JOIN (SELECT * FROM {'.$tablename.'}) b
2503                 ON a.id = b.id
2504                 WHERE a.course = ?';
2506         $this->assertTrue($records = $DB->get_records_sql($sql, array(3)));
2507         $this->assertEqual(2, count($records));
2508         $this->assertEqual(1, reset($records)->id);
2509         $this->assertEqual(2, next($records)->id);
2511         // try embeding sql_xxxx() helper functions, to check they don't break params/binding
2512         $count = $DB->count_records($tablename, array('course' => 3, $DB->sql_compare_text('content') => 'hello'));
2513         $this->assertEqual(1, $count);
2514     }
2516     function test_onelevel_commit() {
2517         $DB = $this->tdb;
2518         $dbman = $DB->get_manager();
2520         $table = $this->get_test_table();
2521         $tablename = $table->getName();
2523         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2524         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2525         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2526         $dbman->create_table($table);
2527         $this->tables[$tablename] = $table;
2529         $transaction = $DB->start_delegated_transaction();
2530         $data = (object)array('course'=>3);
2531         $this->assertEqual(0, $DB->count_records($tablename));
2532         $DB->insert_record($tablename, $data);
2533         $this->assertEqual(1, $DB->count_records($tablename));
2534         $transaction->allow_commit();
2535         $this->assertEqual(1, $DB->count_records($tablename));
2536     }
2538     function test_onelevel_rollback() {
2539         $DB = $this->tdb;
2540         $dbman = $DB->get_manager();
2542         $table = $this->get_test_table();
2543         $tablename = $table->getName();
2545         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2546         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2547         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2548         $dbman->create_table($table);
2549         $this->tables[$tablename] = $table;
2551         // this might in fact encourage ppl to migrate from myisam to innodb
2553         $transaction = $DB->start_delegated_transaction();
2554         $data = (object)array('course'=>3);
2555         $this->assertEqual(0, $DB->count_records($tablename));
2556         $DB->insert_record($tablename, $data);
2557         $this->assertEqual(1, $DB->count_records($tablename));
2558         try {
2559             $transaction->rollback(new Exception('test'));
2560             $this->fail('transaction rollback must rethrow exception');
2561         } catch (Exception $e) {
2562         }
2563         $this->assertEqual(0, $DB->count_records($tablename));
2564     }
2566     function test_nested_transactions() {
2567         $DB = $this->tdb;
2568         $dbman = $DB->get_manager();
2570         $table = $this->get_test_table();
2571         $tablename = $table->getName();
2573         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2574         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2575         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2576         $dbman->create_table($table);
2577         $this->tables[$tablename] = $table;
2579         // two level commit
2580         $this->assertFalse($DB->is_transaction_started());
2581         $transaction1 = $DB->start_delegated_transaction();
2582         $this->assertTrue($DB->is_transaction_started());
2583         $data = (object)array('course'=>3);
2584         $DB->insert_record($tablename, $data);
2585         $transaction2 = $DB->start_delegated_transaction();
2586         $data = (object)array('course'=>4);
2587         $DB->insert_record($tablename, $data);
2588         $transaction2->allow_commit();
2589         $this->assertTrue($DB->is_transaction_started());
2590         $transaction1->allow_commit();
2591         $this->assertFalse($DB->is_transaction_started());
2592         $this->assertEqual(2, $DB->count_records($tablename));
2594         $DB->delete_records($tablename);
2596         // rollback from top level
2597         $transaction1 = $DB->start_delegated_transaction();
2598         $data = (object)array('course'=>3);
2599         $DB->insert_record($tablename, $data);
2600         $transaction2 = $DB->start_delegated_transaction();
2601         $data = (object)array('course'=>4);
2602         $DB->insert_record($tablename, $data);
2603         $transaction2->allow_commit();
2604         try {
2605             $transaction1->rollback(new Exception('test'));
2606             $this->fail('transaction rollback must rethrow exception');
2607         } catch (Exception $e) {
2608             $this->assertEqual(get_class($e), 'Exception');
2609         }
2610         $this->assertEqual(0, $DB->count_records($tablename));
2612         $DB->delete_records($tablename);
2614         // rollback from nested level
2615         $transaction1 = $DB->start_delegated_transaction();
2616         $data = (object)array('course'=>3);
2617         $DB->insert_record($tablename, $data);
2618         $transaction2 = $DB->start_delegated_transaction();
2619         $data = (object)array('course'=>4);
2620         $DB->insert_record($tablename, $data);
2621         try {
2622             $transaction2->rollback(new Exception('test'));
2623             $this->fail('transaction rollback must rethrow exception');
2624         } catch (Exception $e) {
2625             $this->assertEqual(get_class($e), 'Exception');
2626         }
2627         $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet
2628         try {
2629             $transaction1->allow_commit();
2630         } catch (Exception $e) {
2631             $this->assertEqual(get_class($e), 'dml_transaction_exception');
2632         }
2633         $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet
2634         // the forced rollback is done from the default_exception handler and similar places,
2635         // let's do it manually here
2636         $this->assertTrue($DB->is_transaction_started());
2637         $DB->force_transaction_rollback();
2638         $this->assertFalse($DB->is_transaction_started());
2639         $this->assertEqual(0, $DB->count_records($tablename)); // finally rolled back
2641         $DB->delete_records($tablename);
2642     }
2644     function test_transactions_forbidden() {
2645         $DB = $this->tdb;
2646         $dbman = $DB->get_manager();
2648         $table = $this->get_test_table();
2649         $tablename = $table->getName();
2651         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2652         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2653         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2654         $dbman->create_table($table);
2655         $this->tables[$tablename] = $table;
2657         $DB->transactions_forbidden();
2658         $transaction = $DB->start_delegated_transaction();
2659         $data = (object)array('course'=>1);
2660         $DB->insert_record($tablename, $data);
2661         try {
2662             $DB->transactions_forbidden();
2663         } catch (Exception $e) {
2664             $this->assertEqual(get_class($e), 'dml_transaction_exception');
2665         }
2666         // the previous test does not force rollback
2667         $transaction->allow_commit();
2668         $this->assertFalse($DB->is_transaction_started());
2669         $this->assertEqual(1, $DB->count_records($tablename));
2670     }
2672     function test_wrong_transactions() {
2673         $DB = $this->tdb;
2674         $dbman = $DB->get_manager();
2676         $table = $this->get_test_table();
2677         $tablename = $table->getName();
2679         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2680         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2681         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2682         $dbman->create_table($table);
2683         $this->tables[$tablename] = $table;
2686         // wrong order of nested commits
2687         $transaction1 = $DB->start_delegated_transaction();
2688         $data = (object)array('course'=>3);
2689         $DB->insert_record($tablename, $data);
2690         $transaction2 = $DB->start_delegated_transaction();
2691         $data = (object)array('course'=>4);
2692         $DB->insert_record($tablename, $data);
2693         try {
2694             $transaction1->allow_commit();
2695             $this->fail('wrong order of commits must throw exception');
2696         } catch (Exception $e) {
2697             $this->assertEqual(get_class($e), 'dml_transaction_exception');
2698         }
2699         try {
2700             $transaction2->allow_commit();
2701             $this->fail('first wrong commit forces rollback');
2702         } catch (Exception $e) {
2703             $this->assertEqual(get_class($e), 'dml_transaction_exception');
2704         }
2705         // this is done in default exception handler usually
2706         $this->assertTrue($DB->is_transaction_started());
2707         $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet
2708         $DB->force_transaction_rollback();
2709         $this->assertEqual(0, $DB->count_records($tablename));
2710         $DB->delete_records($tablename);
2713         // wrong order of nested rollbacks
2714         $transaction1 = $DB->start_delegated_transaction();
2715         $data = (object)array('course'=>3);
2716         $DB->insert_record($tablename, $data);
2717         $transaction2 = $DB->start_delegated_transaction();
2718         $data = (object)array('course'=>4);
2719         $DB->insert_record($tablename, $data);
2720         try {
2721             // this first rollback should prevent all otehr rollbacks
2722             $transaction1->rollback(new Exception('test'));
2723         } catch (Exception $e) {
2724             $this->assertEqual(get_class($e), 'Exception');
2725         }
2726         try {
2727             $transaction2->rollback(new Exception('test'));
2728         } catch (Exception $e) {
2729             $this->assertEqual(get_class($e), 'Exception');
2730         }
2731         try {
2732             $transaction1->rollback(new Exception('test'));
2733         } catch (Exception $e) {
2734             // the rollback was used already once, no way to use it again
2735             $this->assertEqual(get_class($e), 'dml_transaction_exception');
2736         }
2737         // this is done in default exception handler usually
2738         $this->assertTrue($DB->is_transaction_started());
2739         $DB->force_transaction_rollback();
2740         $DB->delete_records($tablename);
2743         // unknown transaction object
2744         $transaction1 = $DB->start_delegated_transaction();
2745         $data = (object)array('course'=>3);
2746         $DB->insert_record($tablename, $data);
2747         $transaction2 = new moodle_transaction($DB);
2748         try {
2749             $transaction2->allow_commit();
2750             $this->fail('foreign transaction must fail');
2751         } catch (Exception $e) {
2752             $this->assertEqual(get_class($e), 'dml_transaction_exception');
2753         }
2754         try {
2755             $transaction1->allow_commit();
2756             $this->fail('first wrong commit forces rollback');
2757         } catch (Exception $e) {
2758             $this->assertEqual(get_class($e), 'dml_transaction_exception');
2759         }
2760         $DB->force_transaction_rollback();
2761         $DB->delete_records($tablename);
2762     }
2764     function test_concurent_transactions() {
2765         // Notes about this test:
2766         // 1- MySQL needs to use one engine with transactions support (InnoDB).
2767         // 2- MSSQL needs to have enabled versioning for read committed
2768         //    transactions (ALTER DATABASE xxx SET READ_COMMITTED_SNAPSHOT ON)
2769         $DB = $this->tdb;
2770         $dbman = $DB->get_manager();
2772         $table = $this->get_test_table();
2773         $tablename = $table->getName();
2775         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2776         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2777         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2778         $dbman->create_table($table);
2779         $this->tables[$tablename] = $table;
2781         $transaction = $DB->start_delegated_transaction();
2782         $data = (object)array('course'=>1);
2783         $this->assertEqual(0, $DB->count_records($tablename));
2784         $DB->insert_record($tablename, $data);
2785         $this->assertEqual(1, $DB->count_records($tablename));
2787         //open second connection
2788         $cfg = $DB->export_dbconfig();
2789         if (!isset($cfg->dboptions)) {
2790             $cfg->dboptions = array();
2791         }
2792         $DB2 = moodle_database::get_driver_instance($cfg->dbtype, $cfg->dblibrary);
2793         $DB2->connect($cfg->dbhost, $cfg->dbuser, $cfg->dbpass, $cfg->dbname, $cfg->prefix, $cfg->dboptions);
2795         // second instance should not see pending inserts
2796         $this->assertEqual(0, $DB2->count_records($tablename));
2797         $data = (object)array('course'=>2);
2798         $DB2->insert_record($tablename, $data);
2799         $this->assertEqual(1, $DB2->count_records($tablename));
2801         // first should see the changes done from second
2802         $this->assertEqual(2, $DB->count_records($tablename));
2804         // now commit and we should see it finally in second connections
2805         $transaction->allow_commit();
2806         $this->assertEqual(2, $DB2->count_records($tablename));
2808         $DB2->dispose();
2809     }
2812 /**
2813  * This class is not a proper subclass of moodle_database. It is
2814  * intended to be used only in unit tests, in order to gain access to the
2815  * protected methods of moodle_database, and unit test them.
2816  */
2817 class moodle_database_for_testing extends moodle_database {
2818     protected $prefix = 'mdl_';
2820     public function public_fix_table_names($sql) {
2821         return $this->fix_table_names($sql);
2822     }
2824     public function driver_installed(){}
2825     public function get_dbfamily(){}
2826     protected function get_dbtype(){}
2827     protected function get_dblibrary(){}
2828     public function get_name(){}
2829     public function get_configuration_help(){}
2830     public function get_configuration_hints(){}
2831     public function connect($dbhost, $dbuser, $dbpass, $dbname, $prefix, array $dboptions=null){}
2832     public function get_server_info(){}
2833     protected function allowed_param_types(){}
2834     public function get_last_error(){}
2835     public function get_tables($usecache=true){}
2836     public function get_indexes($table){}
2837     public function get_columns($table, $usecache=true){}
2838     protected function normalise_value($column, $value){}
2839     public function set_debug($state){}
2840     public function get_debug(){}
2841     public function set_logging($state){}
2842     public function change_database_structure($sql){}
2843     public function execute($sql, array $params=null){}
2844     public function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0){}
2845     public function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnum=0){}
2846     public function get_fieldset_sql($sql, array $params=null){}
2847     public function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false){}
2848     public function insert_record($table, $dataobject, $returnid=true, $bulk=false){}
2849     public function import_record($table, $dataobject){}
2850     public function update_record_raw($table, $params, $bulk=false){}
2851     public function update_record($table, $dataobject, $bulk=false){}
2852     public function set_field_select($table, $newfield, $newvalue, $select, array $params=null){}
2853     public function delete_records_select($table, $select, array $params=null){}
2854     public function sql_concat(){}
2855     public function sql_concat_join($separator="' '", $elements=array()){}
2856     public function sql_substr($expr, $start, $length=false){}
2857     public function begin_transaction() {}
2858     public function commit_transaction() {}
2859     public function rollback_transaction() {}