lib MDL-26458 adding unit tests to test cursors.
[moodle.git] / lib / dml / simpletest / testdml.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * @package    core
20  * @subpackage dml
21  * @copyright  2008 Petr Skoda (http://skodak.org)
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 class dml_test extends UnitTestCase {
28     private $tables = array();
29     private $tdb;
30     private $data;
31     public  static $includecoverage = array('lib/dml');
32     public  static $excludecoverage = array('lib/dml/simpletest');
34     protected $olddebug;
35     protected $olddisplay;
37     function setUp() {
38         global $DB, $UNITTEST;
40         if (isset($UNITTEST->func_test_db)) {
41             $this->tdb = $UNITTEST->func_test_db;
42         } else {
43             $this->tdb = $DB;
44         }
45     }
47     function tearDown() {
48         $dbman = $this->tdb->get_manager();
50         foreach ($this->tables as $tablename) {
51             if ($dbman->table_exists($tablename)) {
52                 $table = new xmldb_table($tablename);
53                 $dbman->drop_table($table);
54             }
55         }
56         $this->tables = array();
57     }
59     /**
60      * Get a xmldb_table object for testing, deleting any existing table
61      * of the same name, for example if one was left over from a previous test
62      * run that crashed.
63      *
64      * @param database_manager $dbman the database_manager to use.
65      * @param string $suffix table name suffix, use if you need more test tables
66      * @return xmldb_table the table object.
67      */
68     private function get_test_table($suffix = '') {
69         $dbman = $this->tdb->get_manager();
71         $tablename = "unit_table";
72         if ($suffix !== '') {
73             $tablename .= $suffix;
74         }
76         $table = new xmldb_table($tablename);
77         if ($dbman->table_exists($table)) {
78             $dbman->drop_table($table);
79         }
80         $table->setComment("This is a test'n drop table. You can drop it safely");
81         $this->tables[$tablename] = $tablename;
82         return new xmldb_table($tablename);
83     }
85     protected function enable_debugging() {
86         global $CFG;
88         $this->olddebug   = $CFG->debug;       // Save current debug settings
89         $this->olddisplay = $CFG->debugdisplay;
90         $CFG->debug = DEBUG_DEVELOPER;
91         $CFG->debugdisplay = true;
92         ob_start(); // hide debug warning
94     }
96     protected function get_debugging() {
97         global $CFG;
99         $debuginfo = ob_get_contents();
100         ob_end_clean();
101         $CFG->debug = $this->olddebug;         // Restore original debug settings
102         $CFG->debugdisplay = $this->olddisplay;
104         return $debuginfo;
105     }
107     // NOTE: please keep order of test methods here matching the order of moodle_database class methods
109     function test_diagnose() {
110         $DB = $this->tdb;
111         $result = $DB->diagnose();
112         $this->assertNull($result, 'Database self diagnostics failed %s');
113     }
115     function test_get_server_info() {
116         $DB = $this->tdb;
117         $result = $DB->get_server_info();
118         $this->assertTrue(is_array($result));
119         $this->assertTrue(array_key_exists('description', $result));
120         $this->assertTrue(array_key_exists('version', $result));
121     }
123     public function test_get_in_or_equal() {
124         $DB = $this->tdb;
126         // SQL_PARAMS_QM - IN or =
128         // Correct usage of multiple values
129         $in_values = array('value1', 'value2', '3', 4, null, false, true);
130         list($usql, $params) = $DB->get_in_or_equal($in_values);
131         $this->assertEqual('IN ('.implode(',',array_fill(0, count($in_values), '?')).')', $usql);
132         $this->assertEqual(count($in_values), count($params));
133         foreach ($params as $key => $value) {
134             $this->assertIdentical($in_values[$key], $value);
135         }
137         // Correct usage of single value (in an array)
138         $in_values = array('value1');
139         list($usql, $params) = $DB->get_in_or_equal($in_values);
140         $this->assertEqual("= ?", $usql);
141         $this->assertEqual(1, count($params));
142         $this->assertEqual($in_values[0], $params[0]);
144         // Correct usage of single value
145         $in_value = 'value1';
146         list($usql, $params) = $DB->get_in_or_equal($in_values);
147         $this->assertEqual("= ?", $usql);
148         $this->assertEqual(1, count($params));
149         $this->assertEqual($in_value, $params[0]);
151         // SQL_PARAMS_QM - NOT IN or <>
153         // Correct usage of multiple values
154         $in_values = array('value1', 'value2', 'value3', 'value4');
155         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
156         $this->assertEqual("NOT IN (?,?,?,?)", $usql);
157         $this->assertEqual(4, count($params));
158         foreach ($params as $key => $value) {
159             $this->assertEqual($in_values[$key], $value);
160         }
162         // Correct usage of single value (in array()
163         $in_values = array('value1');
164         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
165         $this->assertEqual("<> ?", $usql);
166         $this->assertEqual(1, count($params));
167         $this->assertEqual($in_values[0], $params[0]);
169         // Correct usage of single value
170         $in_value = 'value1';
171         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
172         $this->assertEqual("<> ?", $usql);
173         $this->assertEqual(1, count($params));
174         $this->assertEqual($in_value, $params[0]);
176         // SQL_PARAMS_NAMED - IN or =
178         // Correct usage of multiple values
179         $in_values = array('value1', 'value2', 'value3', 'value4');
180         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', true);
181         $this->assertEqual("IN (:param01,:param02,:param03,:param04)", $usql);
182         $this->assertEqual(4, count($params));
183         reset($in_values);
184         foreach ($params as $key => $value) {
185             $this->assertEqual(current($in_values), $value);
186             next($in_values);
187         }
189         // Correct usage of single values (in array)
190         $in_values = array('value1');
191         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', true);
192         $this->assertEqual("= :param01", $usql);
193         $this->assertEqual(1, count($params));
194         $this->assertEqual($in_values[0], $params['param01']);
196         // Correct usage of single value
197         $in_value = 'value1';
198         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', true);
199         $this->assertEqual("= :param01", $usql);
200         $this->assertEqual(1, count($params));
201         $this->assertEqual($in_value, $params['param01']);
203         // SQL_PARAMS_NAMED - NOT IN or <>
205         // Correct usage of multiple values
206         $in_values = array('value1', 'value2', 'value3', 'value4');
207         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
208         $this->assertEqual("NOT IN (:param01,:param02,:param03,:param04)", $usql);
209         $this->assertEqual(4, count($params));
210         reset($in_values);
211         foreach ($params as $key => $value) {
212             $this->assertEqual(current($in_values), $value);
213             next($in_values);
214         }
216         // Correct usage of single values (in array)
217         $in_values = array('value1');
218         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
219         $this->assertEqual("<> :param01", $usql);
220         $this->assertEqual(1, count($params));
221         $this->assertEqual($in_values[0], $params['param01']);
223         // Correct usage of single value
224         $in_value = 'value1';
225         list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
226         $this->assertEqual("<> :param01", $usql);
227         $this->assertEqual(1, count($params));
228         $this->assertEqual($in_value, $params['param01']);
230     }
232     public function test_fix_table_names() {
233         $DB = new moodle_database_for_testing();
234         $prefix = $DB->get_prefix();
236         // Simple placeholder
237         $placeholder = "{user_123}";
238         $this->assertIdentical($prefix."user_123", $DB->public_fix_table_names($placeholder));
240         // wrong table name
241         $placeholder = "{user-a}";
242         $this->assertIdentical($placeholder, $DB->public_fix_table_names($placeholder));
244         // wrong table name
245         $placeholder = "{123user}";
246         $this->assertIdentical($placeholder, $DB->public_fix_table_names($placeholder));
248         // Full SQL
249         $sql = "SELECT * FROM {user}, {funny_table_name}, {mdl_stupid_table} WHERE {user}.id = {funny_table_name}.userid";
250         $expected = "SELECT * FROM {$prefix}user, {$prefix}funny_table_name, {$prefix}mdl_stupid_table WHERE {$prefix}user.id = {$prefix}funny_table_name.userid";
251         $this->assertIdentical($expected, $DB->public_fix_table_names($sql));
252     }
254     function test_fix_sql_params() {
255         $DB = $this->tdb;
257         $table = $this->get_test_table();
258         $tablename = $table->getName();
260         // Correct table placeholder substitution
261         $sql = "SELECT * FROM {{$tablename}}";
262         $sqlarray = $DB->fix_sql_params($sql);
263         $this->assertEqual("SELECT * FROM {$DB->get_prefix()}".$tablename, $sqlarray[0]);
265         // Conversions of all param types
266         $sql = array();
267         $sql[SQL_PARAMS_NAMED]  = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = :param1, course = :param2";
268         $sql[SQL_PARAMS_QM]     = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = ?, course = ?";
269         $sql[SQL_PARAMS_DOLLAR] = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = \$1, course = \$2";
271         $params = array();
272         $params[SQL_PARAMS_NAMED]  = array('param1'=>'first record', 'param2'=>1);
273         $params[SQL_PARAMS_QM]     = array('first record', 1);
274         $params[SQL_PARAMS_DOLLAR] = array('first record', 1);
276         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_NAMED], $params[SQL_PARAMS_NAMED]);
277         $this->assertIdentical($rsql, $sql[$rtype]);
278         $this->assertIdentical($rparams, $params[$rtype]);
280         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_QM], $params[SQL_PARAMS_QM]);
281         $this->assertIdentical($rsql, $sql[$rtype]);
282         $this->assertIdentical($rparams, $params[$rtype]);
284         list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_DOLLAR], $params[SQL_PARAMS_DOLLAR]);
285         $this->assertIdentical($rsql, $sql[$rtype]);
286         $this->assertIdentical($rparams, $params[$rtype]);
289         // Malformed table placeholder
290         $sql = "SELECT * FROM [testtable]";
291         $sqlarray = $DB->fix_sql_params($sql);
292         $this->assertIdentical($sql, $sqlarray[0]);
295         // Mixed param types (colon and dollar)
296         $sql = "SELECT * FROM {{$tablename}} WHERE name = :param1, course = \$1";
297         $params = array('param1' => 'record1', 'param2' => 3);
298         try {
299             $DB->fix_sql_params($sql, $params);
300             $this->fail("Expecting an exception, none occurred");
301         } catch (Exception $e) {
302             $this->assertTrue($e instanceof dml_exception);
303         }
305         // Mixed param types (question and dollar)
306         $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = \$1";
307         $params = array('param1' => 'record2', 'param2' => 5);
308         try {
309             $DB->fix_sql_params($sql, $params);
310             $this->fail("Expecting an exception, none occurred");
311         } catch (Exception $e) {
312             $this->assertTrue($e instanceof dml_exception);
313         }
315         // Too few params in sql
316         $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = ?, id = ?";
317         $params = array('record2', 3);
318         try {
319             $DB->fix_sql_params($sql, $params);
320             $this->fail("Expecting an exception, none occurred");
321         } catch (Exception $e) {
322             $this->assertTrue($e instanceof dml_exception);
323         }
325         // Too many params in array: no error, just use what is necessary
326         $params[] = 1;
327         $params[] = time();
328         try {
329             $sqlarray = $DB->fix_sql_params($sql, $params);
330             $this->assertTrue(is_array($sqlarray));
331             $this->assertEqual(count($sqlarray[1]), 3);
332         } catch (Exception $e) {
333             $this->fail("Unexpected ".get_class($e)." exception");
334         }
336         // Named params missing from array
337         $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
338         $params = array('wrongname' => 'record1', 'course' => 1);
339         try {
340             $DB->fix_sql_params($sql, $params);
341             $this->fail("Expecting an exception, none occurred");
342         } catch (Exception $e) {
343             $this->assertTrue($e instanceof dml_exception);
344         }
346         // Duplicate named param in query - this is a very important feature!!
347         // it helps with debugging of sloppy code
348         $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :name";
349         $params = array('name' => 'record2', 'course' => 3);
350         try {
351             $DB->fix_sql_params($sql, $params);
352             $this->fail("Expecting an exception, none occurred");
353         } catch (Exception $e) {
354             $this->assertTrue($e instanceof dml_exception);
355         }
357         // Extra named param is ignored
358         $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
359         $params = array('name' => 'record1', 'course' => 1, 'extrastuff'=>'haha');
360         try {
361             $sqlarray = $DB->fix_sql_params($sql, $params);
362             $this->assertTrue(is_array($sqlarray));
363             $this->assertEqual(count($sqlarray[1]), 2);
364         } catch (Exception $e) {
365             $this->fail("Unexpected ".get_class($e)." exception");
366         }
368         // Booleans in NAMED params are casting to 1/0 int
369         $sql = "SELECT * FROM {{$tablename}} WHERE course = ? OR course = ?";
370         $params = array(true, false);
371         list($sql, $params) = $DB->fix_sql_params($sql, $params);
372         $this->assertTrue(reset($params) === 1);
373         $this->assertTrue(next($params) === 0);
375         // Booleans in QM params are casting to 1/0 int
376         $sql = "SELECT * FROM {{$tablename}} WHERE course = :course1 OR course = :course2";
377         $params = array('course1' => true, 'course2' => false);
378         list($sql, $params) = $DB->fix_sql_params($sql, $params);
379         $this->assertTrue(reset($params) === 1);
380         $this->assertTrue(next($params) === 0);
382         // Booleans in DOLLAR params are casting to 1/0 int
383         $sql = "SELECT * FROM {{$tablename}} WHERE course = \$1 OR course = \$2";
384         $params = array(true, false);
385         list($sql, $params) = $DB->fix_sql_params($sql, $params);
386         $this->assertTrue(reset($params) === 1);
387         $this->assertTrue(next($params) === 0);
389         // No data types are touched except bool
390         $sql = "SELECT * FROM {{$tablename}} WHERE name IN (?,?,?,?,?,?)";
391         $inparams = array('abc', 'ABC', NULL, '1', 1, 1.4);
392         list($sql, $params) = $DB->fix_sql_params($sql, $inparams);
393         $this->assertIdentical(array_values($params), array_values($inparams));
394     }
396     public function test_get_tables() {
397         $DB = $this->tdb;
398         $dbman = $this->tdb->get_manager();
400         // Need to test with multiple DBs
401         $table = $this->get_test_table();
402         $tablename = $table->getName();
404         $original_count = count($DB->get_tables());
406         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
407         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
409         $dbman->create_table($table);
410         $this->assertTrue(count($DB->get_tables()) == $original_count + 1);
412         $dbman->drop_table($table);
413         $this->assertTrue(count($DB->get_tables()) == $original_count);
414     }
416     public function test_get_indexes() {
417         $DB = $this->tdb;
418         $dbman = $this->tdb->get_manager();
420         $table = $this->get_test_table();
421         $tablename = $table->getName();
423         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
424         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
425         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
426         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
427         $table->add_index('course-id', XMLDB_INDEX_UNIQUE, array('course', 'id'));
428         $dbman->create_table($table);
430         $indices = $DB->get_indexes($tablename);
431         $this->assertTrue(is_array($indices));
432         $this->assertEqual(count($indices), 2);
433         // we do not care about index names for now
434         $first = array_shift($indices);
435         $second = array_shift($indices);
436         if (count($first['columns']) == 2) {
437             $composed = $first;
438             $single   = $second;
439         } else {
440             $composed = $second;
441             $single   = $first;
442         }
443         $this->assertFalse($single['unique']);
444         $this->assertTrue($composed['unique']);
445         $this->assertEqual(1, count($single['columns']));
446         $this->assertEqual(2, count($composed['columns']));
447         $this->assertEqual('course', $single['columns'][0]);
448         $this->assertEqual('course', $composed['columns'][0]);
449         $this->assertEqual('id', $composed['columns'][1]);
450     }
452     public function test_get_columns() {
453         $DB = $this->tdb;
454         $dbman = $this->tdb->get_manager();
456         $table = $this->get_test_table();
457         $tablename = $table->getName();
459         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
460         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
461         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
462         $table->add_field('description', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
463         $table->add_field('enumfield', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'test2');
464         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
465         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
466         $dbman->create_table($table);
468         $columns = $DB->get_columns($tablename);
469         $this->assertTrue(is_array($columns));
471         $fields = $table->getFields();
472         $this->assertEqual(count($columns), count($fields));
474         $field = $columns['id'];
475         $this->assertEqual('R', $field->meta_type);
476         $this->assertTrue($field->auto_increment);
477         $this->assertTrue($field->unique);
479         $field = $columns['course'];
480         $this->assertEqual('I', $field->meta_type);
481         $this->assertFalse($field->auto_increment);
482         $this->assertTrue($field->has_default);
483         $this->assertEqual(0, $field->default_value);
484         $this->assertTrue($field->not_null);
486         $field = $columns['name'];
487         $this->assertEqual('C', $field->meta_type);
488         $this->assertFalse($field->auto_increment);
489         $this->assertTrue($field->has_default);
490         $this->assertIdentical('lala', $field->default_value);
491         $this->assertFalse($field->not_null);
493         $field = $columns['description'];
494         $this->assertEqual('X', $field->meta_type);
495         $this->assertFalse($field->auto_increment);
496         $this->assertFalse($field->has_default);
497         $this->assertIdentical(null, $field->default_value);
498         $this->assertFalse($field->not_null);
500         $field = $columns['enumfield'];
501         $this->assertEqual('C', $field->meta_type);
502         $this->assertFalse($field->auto_increment);
503         $this->assertIdentical('test2', $field->default_value);
504         $this->assertTrue($field->not_null);
506         $field = $columns['onenum'];
507         $this->assertEqual('N', $field->meta_type);
508         $this->assertFalse($field->auto_increment);
509         $this->assertTrue($field->has_default);
510         $this->assertEqual(200.0, $field->default_value);
511         $this->assertFalse($field->not_null);
513         for ($i = 0; $i < count($columns); $i++) {
514             if ($i == 0) {
515                 $next_column = reset($columns);
516                 $next_field  = reset($fields);
517             } else {
518                 $next_column = next($columns);
519                 $next_field  = next($fields);
520             }
522             $this->assertEqual($next_column->name, $next_field->name);
523         }
524     }
526     public function test_get_manager() {
527         $DB = $this->tdb;
528         $dbman = $this->tdb->get_manager();
530         $this->assertTrue($dbman instanceof database_manager);
531     }
533     public function test_setup_is_unicodedb() {
534         $DB = $this->tdb;
535         $this->assertTrue($DB->setup_is_unicodedb());
536     }
538     public function test_set_debug() { //tests get_debug() too
539         $DB = $this->tdb;
540         $dbman = $this->tdb->get_manager();
542         $table = $this->get_test_table();
543         $tablename = $table->getName();
545         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
546         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
547         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
548         $dbman->create_table($table);
550         $sql = "SELECT * FROM {{$tablename}}";
552         $prevdebug = $DB->get_debug();
554         ob_start();
555         $DB->set_debug(true);
556         $this->assertTrue($DB->get_debug());
557         $DB->execute($sql);
558         $DB->set_debug(false);
559         $this->assertFalse($DB->get_debug());
560         $debuginfo = ob_get_contents();
561         ob_end_clean();
562         $this->assertFalse($debuginfo === '');
564         ob_start();
565         $DB->execute($sql);
566         $debuginfo = ob_get_contents();
567         ob_end_clean();
568         $this->assertTrue($debuginfo === '');
570         $DB->set_debug($prevdebug);
571     }
573     public function test_execute() {
574         $DB = $this->tdb;
575         $dbman = $this->tdb->get_manager();
577         $table1 = $this->get_test_table('1');
578         $tablename1 = $table1->getName();
579         $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
580         $table1->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
581         $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
582         $table1->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
583         $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
584         $dbman->create_table($table1);
586         $table2 = $this->get_test_table('2');
587         $tablename2 = $table2->getName();
588         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
589         $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
590         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
591         $dbman->create_table($table2);
593         $DB->insert_record($tablename1, array('course' => 3, 'name' => 'aaa'));
594         $DB->insert_record($tablename1, array('course' => 1, 'name' => 'bbb'));
595         $DB->insert_record($tablename1, array('course' => 7, 'name' => 'ccc'));
596         $DB->insert_record($tablename1, array('course' => 3, 'name' => 'ddd'));
598         // select results are ignored
599         $sql = "SELECT * FROM {{$tablename1}} WHERE course = :course";
600         $this->assertTrue($DB->execute($sql, array('course'=>3)));
602         // throw exception on error
603         $sql = "XXUPDATE SET XSSD";
604         try {
605             $DB->execute($sql);
606             $this->fail("Expecting an exception, none occurred");
607         } catch (Exception $e) {
608             $this->assertTrue($e instanceof dml_write_exception);
609         }
611         // update records
612         $sql = "UPDATE {{$tablename1}}
613                    SET course = 6
614                  WHERE course = ?";
615         $this->assertTrue($DB->execute($sql, array('3')));
616         $this->assertEqual($DB->count_records($tablename1, array('course' => 6)), 2);
618         // insert from one into second table
619         $sql = "INSERT INTO {{$tablename2}} (course)
621                 SELECT course
622                   FROM {{$tablename1}}";
623         $this->assertTrue($DB->execute($sql));
624         $this->assertEqual($DB->count_records($tablename2), 4);
625     }
627     public function test_get_recordset() {
628         $DB = $this->tdb;
629         $dbman = $DB->get_manager();
631         $table = $this->get_test_table();
632         $tablename = $table->getName();
634         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
635         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
636         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
637         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
638         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
639         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
640         $dbman->create_table($table);
642         $data = array(array('id' => 1, 'course' => 3, 'name' => 'record1', 'onetext'=>'abc'),
643                       array('id' => 2, 'course' => 3, 'name' => 'record2', 'onetext'=>'abcd'),
644                       array('id' => 3, 'course' => 5, 'name' => 'record3', 'onetext'=>'abcde'));
646         foreach ($data as $record) {
647             $DB->insert_record($tablename, $record);
648         }
650         // standard recordset iteration
651         $rs = $DB->get_recordset($tablename);
652         $this->assertTrue($rs instanceof moodle_recordset);
653         reset($data);
654         foreach($rs as $record) {
655             $data_record = current($data);
656             foreach ($record as $k => $v) {
657                 $this->assertEqual($data_record[$k], $v);
658             }
659             next($data);
660         }
661         $rs->close();
663         // iterator style usage
664         $rs = $DB->get_recordset($tablename);
665         $this->assertTrue($rs instanceof moodle_recordset);
666         reset($data);
667         while ($rs->valid()) {
668             $record = $rs->current();
669             $data_record = current($data);
670             foreach ($record as $k => $v) {
671                 $this->assertEqual($data_record[$k], $v);
672             }
673             next($data);
674             $rs->next();
675         }
676         $rs->close();
678         // make sure rewind is ignored
679         $rs = $DB->get_recordset($tablename);
680         $this->assertTrue($rs instanceof moodle_recordset);
681         reset($data);
682         $i = 0;
683         foreach($rs as $record) {
684             $i++;
685             $rs->rewind();
686             if ($i > 10) {
687                 $this->fail('revind not ignored in recordsets');
688                 break;
689             }
690             $data_record = current($data);
691             foreach ($record as $k => $v) {
692                 $this->assertEqual($data_record[$k], $v);
693             }
694             next($data);
695         }
696         $rs->close();
698         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
699         $conditions = array('onetext' => '1');
700         try {
701             $rs = $DB->get_recordset($tablename, $conditions);
702             $this->fail('An Exception is missing, expected due to equating of text fields');
703         } catch (exception $e) {
704             $this->assertTrue($e instanceof dml_exception);
705             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
706         }
708         // notes:
709         //  * limits are tested in test_get_recordset_sql()
710         //  * where_clause() is used internally and is tested in test_get_records()
711     }
713     public function test_get_recordset_iterator_keys() {
714         $DB = $this->tdb;
715         $dbman = $DB->get_manager();
717         $table = $this->get_test_table();
718         $tablename = $table->getName();
720         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
721         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
722         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
723         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
724         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
725         $dbman->create_table($table);
727         $data = array(array('id'=> 1, 'course' => 3, 'name' => 'record1'),
728                       array('id'=> 2, 'course' => 3, 'name' => 'record2'),
729                       array('id'=> 3, 'course' => 5, 'name' => 'record3'));
730         foreach ($data as $record) {
731             $DB->insert_record($tablename, $record);
732         }
734         // Test repeated numeric keys are returned ok
735         $rs = $DB->get_recordset($tablename, NULL, NULL, 'course, name, id');
737         reset($data);
738         $count = 0;
739         foreach($rs as $key => $record) {
740             $data_record = current($data);
741             $this->assertEqual($data_record['course'], $key);
742             next($data);
743             $count++;
744         }
745         $rs->close();
746         $this->assertEqual($count, 3);
748         // Test string keys are returned ok
749         $rs = $DB->get_recordset($tablename, NULL, NULL, 'name, course, id');
751         reset($data);
752         $count = 0;
753         foreach($rs as $key => $record) {
754             $data_record = current($data);
755             $this->assertEqual($data_record['name'], $key);
756             next($data);
757             $count++;
758         }
759         $rs->close();
760         $this->assertEqual($count, 3);
762         // Test numeric not starting in 1 keys are returned ok
763         $rs = $DB->get_recordset($tablename, NULL, 'id DESC', 'id, course, name');
765         $data = array_reverse($data);
766         reset($data);
767         $count = 0;
768         foreach($rs as $key => $record) {
769             $data_record = current($data);
770             $this->assertEqual($data_record['id'], $key);
771             next($data);
772             $count++;
773         }
774         $rs->close();
775         $this->assertEqual($count, 3);
776     }
778     public function test_get_recordset_list() {
779         $DB = $this->tdb;
780         $dbman = $DB->get_manager();
782         $table = $this->get_test_table();
783         $tablename = $table->getName();
785         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
786         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
787         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
788         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
789         $dbman->create_table($table);
791         $DB->insert_record($tablename, array('course' => 3));
792         $DB->insert_record($tablename, array('course' => 3));
793         $DB->insert_record($tablename, array('course' => 5));
794         $DB->insert_record($tablename, array('course' => 2));
796         $rs = $DB->get_recordset_list($tablename, 'course', array(3, 2));
798         $counter = 0;
799         foreach ($rs as $record) {
800             $counter++;
801         }
802         $this->assertEqual(3, $counter);
803         $rs->close();
805         $rs = $DB->get_recordset_list($tablename, 'course',array()); /// Must return 0 rows without conditions. MDL-17645
807         $counter = 0;
808         foreach ($rs as $record) {
809             $counter++;
810         }
811         $rs->close();
812         $this->assertEqual(0, $counter);
814         // notes:
815         //  * limits are tested in test_get_recordset_sql()
816         //  * where_clause() is used internally and is tested in test_get_records()
817     }
819     public function test_get_recordset_select() {
820         $DB = $this->tdb;
821         $dbman = $DB->get_manager();
823         $table = $this->get_test_table();
824         $tablename = $table->getName();
826         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
827         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
828         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
829         $dbman->create_table($table);
831         $DB->insert_record($tablename, array('course' => 3));
832         $DB->insert_record($tablename, array('course' => 3));
833         $DB->insert_record($tablename, array('course' => 5));
834         $DB->insert_record($tablename, array('course' => 2));
836         $rs = $DB->get_recordset_select($tablename, '');
837         $counter = 0;
838         foreach ($rs as $record) {
839             $counter++;
840         }
841         $rs->close();
842         $this->assertEqual(4, $counter);
844         $this->assertTrue($rs = $DB->get_recordset_select($tablename, 'course = 3'));
845         $counter = 0;
846         foreach ($rs as $record) {
847             $counter++;
848         }
849         $rs->close();
850         $this->assertEqual(2, $counter);
852         // notes:
853         //  * limits are tested in test_get_recordset_sql()
854     }
856     public function test_get_recordset_sql() {
857         $DB = $this->tdb;
858         $dbman = $DB->get_manager();
860         $table = $this->get_test_table();
861         $tablename = $table->getName();
863         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
864         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
865         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
866         $dbman->create_table($table);
868         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
869         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
870         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
871         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
872         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
873         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
874         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
876         $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
877         $counter = 0;
878         foreach ($rs as $record) {
879             $counter++;
880         }
881         $rs->close();
882         $this->assertEqual(2, $counter);
884         // limits - only need to test this case, the rest have been tested by test_get_records_sql()
885         // only limitfrom = skips that number of records
886         $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
887         $records = array();
888         foreach($rs as $key => $record) {
889             $records[$key] = $record;
890         }
891         $rs->close();
892         $this->assertEqual(5, count($records));
893         $this->assertEqual($inskey3, reset($records)->id);
894         $this->assertEqual($inskey7, end($records)->id);
896         // note: fetching nulls, empties, LOBs already tested by test_insert_record() no needed here
897     }
899     public function test_get_records() {
900         $DB = $this->tdb;
901         $dbman = $DB->get_manager();
903         $table = $this->get_test_table();
904         $tablename = $table->getName();
906         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
907         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
908         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
909         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
910         $dbman->create_table($table);
912         $DB->insert_record($tablename, array('course' => 3));
913         $DB->insert_record($tablename, array('course' => 3));
914         $DB->insert_record($tablename, array('course' => 5));
915         $DB->insert_record($tablename, array('course' => 2));
917         // All records
918         $records = $DB->get_records($tablename);
919         $this->assertEqual(4, count($records));
920         $this->assertEqual(3, $records[1]->course);
921         $this->assertEqual(3, $records[2]->course);
922         $this->assertEqual(5, $records[3]->course);
923         $this->assertEqual(2, $records[4]->course);
925         // Records matching certain conditions
926         $records = $DB->get_records($tablename, array('course' => 3));
927         $this->assertEqual(2, count($records));
928         $this->assertEqual(3, $records[1]->course);
929         $this->assertEqual(3, $records[2]->course);
931         // All records sorted by course
932         $records = $DB->get_records($tablename, null, 'course');
933         $this->assertEqual(4, count($records));
934         $current_record = reset($records);
935         $this->assertEqual(4, $current_record->id);
936         $current_record = next($records);
937         $this->assertEqual(1, $current_record->id);
938         $current_record = next($records);
939         $this->assertEqual(2, $current_record->id);
940         $current_record = next($records);
941         $this->assertEqual(3, $current_record->id);
943         // All records, but get only one field
944         $records = $DB->get_records($tablename, null, '', 'id');
945         $this->assertFalse(isset($records[1]->course));
946         $this->assertTrue(isset($records[1]->id));
947         $this->assertEqual(4, count($records));
949         // Booleans into params
950         $records = $DB->get_records($tablename, array('course' => true));
951         $this->assertEqual(0, count($records));
952         $records = $DB->get_records($tablename, array('course' => false));
953         $this->assertEqual(0, count($records));
955         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
956         $conditions = array('onetext' => '1');
957         try {
958             $records = $DB->get_records($tablename, $conditions);
959             $this->fail('An Exception is missing, expected due to equating of text fields');
960         } catch (exception $e) {
961             $this->assertTrue($e instanceof dml_exception);
962             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
963         }
965         // note: delegate limits testing to test_get_records_sql()
966     }
968     public function test_get_records_list() {
969         $DB = $this->tdb;
970         $dbman = $DB->get_manager();
972         $table = $this->get_test_table();
973         $tablename = $table->getName();
975         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
976         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
977         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
978         $dbman->create_table($table);
980         $DB->insert_record($tablename, array('course' => 3));
981         $DB->insert_record($tablename, array('course' => 3));
982         $DB->insert_record($tablename, array('course' => 5));
983         $DB->insert_record($tablename, array('course' => 2));
985         $records = $DB->get_records_list($tablename, 'course', array(3, 2));
986         $this->assertTrue(is_array($records));
987         $this->assertEqual(3, count($records));
988         $this->assertEqual(1, reset($records)->id);
989         $this->assertEqual(2, next($records)->id);
990         $this->assertEqual(4, next($records)->id);
992         $this->assertIdentical(array(), $records = $DB->get_records_list($tablename, 'course', array())); /// Must return 0 rows without conditions. MDL-17645
993         $this->assertEqual(0, count($records));
995         // note: delegate limits testing to test_get_records_sql()
996     }
998     public function test_get_records_sql() {
999         $DB = $this->tdb;
1000         $dbman = $DB->get_manager();
1002         $table = $this->get_test_table();
1003         $tablename = $table->getName();
1005         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1006         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1007         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1008         $dbman->create_table($table);
1010         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
1011         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
1012         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
1013         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
1014         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
1015         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
1016         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
1018         $table2 = $this->get_test_table("2");
1019         $tablename2 = $table2->getName();
1020         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1021         $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1022         $table2->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
1023         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1024         $dbman->create_table($table2);
1026         $DB->insert_record($tablename2, array('course'=>3, 'nametext'=>'badabing'));
1027         $DB->insert_record($tablename2, array('course'=>4, 'nametext'=>'badabang'));
1028         $DB->insert_record($tablename2, array('course'=>5, 'nametext'=>'badabung'));
1029         $DB->insert_record($tablename2, array('course'=>6, 'nametext'=>'badabong'));
1031         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
1032         $this->assertEqual(2, count($records));
1033         $this->assertEqual($inskey1, reset($records)->id);
1034         $this->assertEqual($inskey4, next($records)->id);
1036         // Awful test, requires debug enabled and sent to browser. Let's do that and restore after test
1037         $this->enable_debugging();
1038         $records = $DB->get_records_sql("SELECT course AS id, course AS course FROM {{$tablename}}", null);
1039         $this->assertFalse($this->get_debugging() === '');
1040         $this->assertEqual(6, count($records));
1042         // negative limits = no limits
1043         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, -1, -1);
1044         $this->assertEqual(7, count($records));
1046         // zero limits = no limits
1047         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 0);
1048         $this->assertEqual(7, count($records));
1050         // only limitfrom = skips that number of records
1051         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
1052         $this->assertEqual(5, count($records));
1053         $this->assertEqual($inskey3, reset($records)->id);
1054         $this->assertEqual($inskey7, end($records)->id);
1056         // only limitnum = fetches that number of records
1057         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 3);
1058         $this->assertEqual(3, count($records));
1059         $this->assertEqual($inskey1, reset($records)->id);
1060         $this->assertEqual($inskey3, end($records)->id);
1062         // both limitfrom and limitnum = skips limitfrom records and fetches limitnum ones
1063         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 3, 2);
1064         $this->assertEqual(2, count($records));
1065         $this->assertEqual($inskey4, reset($records)->id);
1066         $this->assertEqual($inskey5, end($records)->id);
1068         // both limitfrom and limitnum in query having subqueris
1069         // note the subquery skips records with course = 0 and 3
1070         $sql = "SELECT * FROM {{$tablename}}
1071                  WHERE course NOT IN (
1072                      SELECT course FROM {{$tablename}}
1073                       WHERE course IN (0, 3))
1074                 ORDER BY course";
1075         $records = $DB->get_records_sql($sql, null, 0, 2); // Skip 0, get 2
1076         $this->assertEqual(2, count($records));
1077         $this->assertEqual($inskey6, reset($records)->id);
1078         $this->assertEqual($inskey5, end($records)->id);
1079         $records = $DB->get_records_sql($sql, null, 2, 2); // Skip 2, get 2
1080         $this->assertEqual(2, count($records));
1081         $this->assertEqual($inskey3, reset($records)->id);
1082         $this->assertEqual($inskey2, end($records)->id);
1084         // test 2 tables with aliases and limits with order bys
1085         $sql = "SELECT t1.id, t1.course AS cid, t2.nametext FROM {{$tablename}} t1, {{$tablename2}} t2
1086             WHERE t2.course=t1.course ORDER BY t1.course, ". $DB->sql_compare_text('t2.nametext');
1087         $records = $DB->get_records_sql($sql, null, 2, 2); // Skip courses 3 and 6, get 4 and 5
1088         $this->assertEqual(2, count($records));
1089         $this->assertEqual('5', end($records)->cid);
1090         $this->assertEqual('4', reset($records)->cid);
1092         // test 2 tables with aliases and limits with order bys (limit which is out  of range)
1093         $records = $DB->get_records_sql($sql, null, 2, 21098765432109876543210); // Skip course {3,6}, get {4,5}
1094         $this->assertEqual(2, count($records));
1095         $this->assertEqual('5', end($records)->cid);
1096         $this->assertEqual('4', reset($records)->cid);
1098         // test 2 tables with aliases and limits with order bys (limit which is out  of range)
1099         $records = $DB->get_records_sql($sql, null, 21098765432109876543210, 2); // Skip all courses
1100         $this->assertEqual(0, count($records));
1102         // test 2 tables with aliases and limits with order bys (limit which is out  of range)
1103         $records = $DB->get_records_sql($sql, null, 21098765432109876543210, 21098765432109876543210); // Skip all courses
1104         $this->assertEqual(0, count($records));
1106         // TODO: Test limits in queries having DISTINCT clauses
1108         // note: fetching nulls, empties, LOBs already tested by test_update_record() no needed here
1109     }
1111     public function test_get_records_menu() {
1112         $DB = $this->tdb;
1113         $dbman = $DB->get_manager();
1115         $table = $this->get_test_table();
1116         $tablename = $table->getName();
1118         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1119         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1120         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1121         $dbman->create_table($table);
1123         $DB->insert_record($tablename, array('course' => 3));
1124         $DB->insert_record($tablename, array('course' => 3));
1125         $DB->insert_record($tablename, array('course' => 5));
1126         $DB->insert_record($tablename, array('course' => 2));
1128         $records = $DB->get_records_menu($tablename, array('course' => 3));
1129         $this->assertTrue(is_array($records));
1130         $this->assertEqual(2, count($records));
1131         $this->assertFalse(empty($records[1]));
1132         $this->assertFalse(empty($records[2]));
1133         $this->assertEqual(3, $records[1]);
1134         $this->assertEqual(3, $records[2]);
1136         // note: delegate limits testing to test_get_records_sql()
1137     }
1139     public function test_get_records_select_menu() {
1140         $DB = $this->tdb;
1141         $dbman = $DB->get_manager();
1143         $table = $this->get_test_table();
1144         $tablename = $table->getName();
1146         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1147         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1148         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1149         $dbman->create_table($table);
1151         $DB->insert_record($tablename, array('course' => 3));
1152         $DB->insert_record($tablename, array('course' => 2));
1153         $DB->insert_record($tablename, array('course' => 3));
1154         $DB->insert_record($tablename, array('course' => 5));
1156         $records = $DB->get_records_select_menu($tablename, "course > ?", array(2));
1157         $this->assertTrue(is_array($records));
1159         $this->assertEqual(3, count($records));
1160         $this->assertFalse(empty($records[1]));
1161         $this->assertTrue(empty($records[2]));
1162         $this->assertFalse(empty($records[3]));
1163         $this->assertFalse(empty($records[4]));
1164         $this->assertEqual(3, $records[1]);
1165         $this->assertEqual(3, $records[3]);
1166         $this->assertEqual(5, $records[4]);
1168         // note: delegate limits testing to test_get_records_sql()
1169     }
1171     public function test_get_records_sql_menu() {
1172         $DB = $this->tdb;
1173         $dbman = $DB->get_manager();
1175         $table = $this->get_test_table();
1176         $tablename = $table->getName();
1178         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1179         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1180         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1181         $dbman->create_table($table);
1183         $DB->insert_record($tablename, array('course' => 3));
1184         $DB->insert_record($tablename, array('course' => 2));
1185         $DB->insert_record($tablename, array('course' => 3));
1186         $DB->insert_record($tablename, array('course' => 5));
1188         $records = $DB->get_records_sql_menu("SELECT * FROM {{$tablename}} WHERE course > ?", array(2));
1189         $this->assertTrue(is_array($records));
1191         $this->assertEqual(3, count($records));
1192         $this->assertFalse(empty($records[1]));
1193         $this->assertTrue(empty($records[2]));
1194         $this->assertFalse(empty($records[3]));
1195         $this->assertFalse(empty($records[4]));
1196         $this->assertEqual(3, $records[1]);
1197         $this->assertEqual(3, $records[3]);
1198         $this->assertEqual(5, $records[4]);
1200         // note: delegate limits testing to test_get_records_sql()
1201     }
1203     public function test_get_record() {
1204         $DB = $this->tdb;
1205         $dbman = $DB->get_manager();
1207         $table = $this->get_test_table();
1208         $tablename = $table->getName();
1210         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1211         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1212         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1213         $dbman->create_table($table);
1215         $DB->insert_record($tablename, array('course' => 3));
1216         $DB->insert_record($tablename, array('course' => 2));
1218         $record = $DB->get_record($tablename, array('id' => 2));
1219         $this->assertTrue($record instanceof stdClass);
1221         $this->assertEqual(2, $record->course);
1222         $this->assertEqual(2, $record->id);
1223     }
1226     public function test_get_record_select() {
1227         $DB = $this->tdb;
1228         $dbman = $DB->get_manager();
1230         $table = $this->get_test_table();
1231         $tablename = $table->getName();
1233         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1234         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1235         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1236         $dbman->create_table($table);
1238         $DB->insert_record($tablename, array('course' => 3));
1239         $DB->insert_record($tablename, array('course' => 2));
1241         $record = $DB->get_record_select($tablename, "id = ?", array(2));
1242         $this->assertTrue($record instanceof stdClass);
1244         $this->assertEqual(2, $record->course);
1246         // note: delegates limit testing to test_get_records_sql()
1247     }
1249     public function test_get_record_sql() {
1250         $DB = $this->tdb;
1251         $dbman = $DB->get_manager();
1253         $table = $this->get_test_table();
1254         $tablename = $table->getName();
1256         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1257         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1258         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1259         $dbman->create_table($table);
1261         $DB->insert_record($tablename, array('course' => 3));
1262         $DB->insert_record($tablename, array('course' => 2));
1264         // standard use
1265         $record = $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(2));
1266         $this->assertTrue($record instanceof stdClass);
1267         $this->assertEqual(2, $record->course);
1268         $this->assertEqual(2, $record->id);
1270         // backwards compatibility with $ignoremultiple
1271         $this->assertFalse(IGNORE_MISSING);
1272         $this->assertTrue(IGNORE_MULTIPLE);
1274         // record not found - ignore
1275         $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MISSING));
1276         $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MULTIPLE));
1278         // record not found error
1279         try {
1280             $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), MUST_EXIST);
1281             $this->fail("Exception expected");
1282         } catch (dml_missing_record_exception $e) {
1283             $this->assertTrue(true);
1284         }
1286         $this->enable_debugging();
1287         $this->assertTrue($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MISSING));
1288         $this->assertFalse($this->get_debugging() === '');
1290         // multiple matches ignored
1291         $this->assertTrue($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MULTIPLE));
1293         // multiple found error
1294         try {
1295             $DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), MUST_EXIST);
1296             $this->fail("Exception expected");
1297         } catch (dml_multiple_records_exception $e) {
1298             $this->assertTrue(true);
1299         }
1300     }
1302     public function test_get_field() {
1303         $DB = $this->tdb;
1304         $dbman = $DB->get_manager();
1306         $table = $this->get_test_table();
1307         $tablename = $table->getName();
1309         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1310         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1311         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1312         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1313         $dbman->create_table($table);
1315         $id1 = $DB->insert_record($tablename, array('course' => 3));
1316         $DB->insert_record($tablename, array('course' => 5));
1317         $DB->insert_record($tablename, array('course' => 5));
1319         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id1)));
1320         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('course' => 3)));
1322         $this->assertIdentical(false, $DB->get_field($tablename, 'course', array('course' => 11), IGNORE_MISSING));
1323         try {
1324             $DB->get_field($tablename, 'course', array('course' => 4), MUST_EXIST);
1325             $this->assertFail('Exception expected due to missing record');
1326         } catch (dml_exception $ex) {
1327             $this->assertTrue(true);
1328         }
1330         $this->enable_debugging();
1331         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MULTIPLE));
1332         $this->assertIdentical($this->get_debugging(), '');
1334         $this->enable_debugging();
1335         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MISSING));
1336         $this->assertFalse($this->get_debugging() === '');
1338         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
1339         $conditions = array('onetext' => '1');
1340         try {
1341             $DB->get_field($tablename, 'course', $conditions);
1342             $this->fail('An Exception is missing, expected due to equating of text fields');
1343         } catch (exception $e) {
1344             $this->assertTrue($e instanceof dml_exception);
1345             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
1346         }
1347     }
1349     public function test_get_field_select() {
1350         $DB = $this->tdb;
1351         $dbman = $DB->get_manager();
1353         $table = $this->get_test_table();
1354         $tablename = $table->getName();
1356         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1357         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1358         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1359         $dbman->create_table($table);
1361         $DB->insert_record($tablename, array('course' => 3));
1363         $this->assertEqual(3, $DB->get_field_select($tablename, 'course', "id = ?", array(1)));
1364     }
1366     public function test_get_field_sql() {
1367         $DB = $this->tdb;
1368         $dbman = $DB->get_manager();
1370         $table = $this->get_test_table();
1371         $tablename = $table->getName();
1373         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1374         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1375         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1376         $dbman->create_table($table);
1378         $DB->insert_record($tablename, array('course' => 3));
1380         $this->assertEqual(3, $DB->get_field_sql("SELECT course FROM {{$tablename}} WHERE id = ?", array(1)));
1381     }
1383     public function test_get_fieldset_select() {
1384         $DB = $this->tdb;
1385         $dbman = $DB->get_manager();
1387         $table = $this->get_test_table();
1388         $tablename = $table->getName();
1390         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1391         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1392         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1393         $dbman->create_table($table);
1395         $DB->insert_record($tablename, array('course' => 1));
1396         $DB->insert_record($tablename, array('course' => 3));
1397         $DB->insert_record($tablename, array('course' => 2));
1398         $DB->insert_record($tablename, array('course' => 6));
1400         $fieldset = $DB->get_fieldset_select($tablename, 'course', "course > ?", array(1));
1401         $this->assertTrue(is_array($fieldset));
1403         $this->assertEqual(3, count($fieldset));
1404         $this->assertEqual(3, $fieldset[0]);
1405         $this->assertEqual(2, $fieldset[1]);
1406         $this->assertEqual(6, $fieldset[2]);
1407     }
1409     public function test_get_fieldset_sql() {
1410         $DB = $this->tdb;
1411         $dbman = $DB->get_manager();
1413         $table = $this->get_test_table();
1414         $tablename = $table->getName();
1416         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1417         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1418         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1419         $dbman->create_table($table);
1421         $DB->insert_record($tablename, array('course' => 1));
1422         $DB->insert_record($tablename, array('course' => 3));
1423         $DB->insert_record($tablename, array('course' => 2));
1424         $DB->insert_record($tablename, array('course' => 6));
1426         $fieldset = $DB->get_fieldset_sql("SELECT * FROM {{$tablename}} WHERE course > ?", array(1));
1427         $this->assertTrue(is_array($fieldset));
1429         $this->assertEqual(3, count($fieldset));
1430         $this->assertEqual(2, $fieldset[0]);
1431         $this->assertEqual(3, $fieldset[1]);
1432         $this->assertEqual(4, $fieldset[2]);
1433     }
1435     public function test_insert_record_raw() {
1436         $DB = $this->tdb;
1437         $dbman = $DB->get_manager();
1439         $table = $this->get_test_table();
1440         $tablename = $table->getName();
1442         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1443         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1444         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1445         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1446         $dbman->create_table($table);
1448         $record = (object)array('course' => 1, 'onechar' => 'xx');
1449         $before = clone($record);
1450         $result = $DB->insert_record_raw($tablename, $record);
1451         $this->assertIdentical(1, $result);
1452         $this->assertIdentical($record, $before);
1454         $record = $DB->get_record($tablename, array('course' => 1));
1455         $this->assertTrue($record instanceof stdClass);
1456         $this->assertIdentical('xx', $record->onechar);
1458         $result = $DB->insert_record_raw($tablename, array('course' => 2, 'onechar' => 'yy'), false);
1459         $this->assertIdentical(true, $result);
1461         // note: bulk not implemented yet
1462         $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'zz'), true, true);
1463         $record = $DB->get_record($tablename, array('course' => 3));
1464         $this->assertTrue($record instanceof stdClass);
1465         $this->assertIdentical('zz', $record->onechar);
1467         // custom sequence (id) - returnid is ignored
1468         $result = $DB->insert_record_raw($tablename, array('id' => 10, 'course' => 3, 'onechar' => 'bb'), true, false, true);
1469         $this->assertIdentical(true, $result);
1470         $record = $DB->get_record($tablename, array('id' => 10));
1471         $this->assertTrue($record instanceof stdClass);
1472         $this->assertIdentical('bb', $record->onechar);
1474         // custom sequence - missing id error
1475         try {
1476             $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'bb'), true, false, true);
1477             $this->assertFail('Exception expected due to missing record');
1478         } catch (coding_exception $ex) {
1479             $this->assertTrue(true);
1480         }
1482         // wrong column error
1483         try {
1484             $DB->insert_record_raw($tablename, array('xxxxx' => 3, 'onechar' => 'bb'));
1485             $this->assertFail('Exception expected due to invalid column');
1486         } catch (dml_write_exception $ex) {
1487             $this->assertTrue(true);
1488         }
1489     }
1491     public function test_insert_record() {
1492         // All the information in this test is fetched from DB by get_recordset() so we
1493         // have such method properly tested against nulls, empties and friends...
1495         $DB = $this->tdb;
1496         $dbman = $DB->get_manager();
1498         $table = $this->get_test_table();
1499         $tablename = $table->getName();
1501         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1502         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1503         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
1504         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1505         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1506         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1507         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1508         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1509         $dbman->create_table($table);
1511         $this->assertIdentical(1, $DB->insert_record($tablename, array('course' => 1), true));
1512         $record = $DB->get_record($tablename, array('course' => 1));
1513         $this->assertEqual(1, $record->id);
1514         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
1515         $this->assertEqual(200, $record->onenum);
1516         $this->assertIdentical('onestring', $record->onechar);
1517         $this->assertNull($record->onetext);
1518         $this->assertNull($record->onebinary);
1520         // without returning id, bulk not implemented
1521         $result = $this->assertIdentical(true, $DB->insert_record($tablename, array('course' => 99), false, true));
1522         $record = $DB->get_record($tablename, array('course' => 99));
1523         $this->assertEqual(2, $record->id);
1524         $this->assertEqual(99, $record->course);
1526         // Check nulls are set properly for all types
1527         $record = new stdClass();
1528         $record->oneint = null;
1529         $record->onenum = null;
1530         $record->onechar = null;
1531         $record->onetext = null;
1532         $record->onebinary = null;
1533         $recid = $DB->insert_record($tablename, $record);
1534         $record = $DB->get_record($tablename, array('id' => $recid));
1535         $this->assertEqual(0, $record->course);
1536         $this->assertNull($record->oneint);
1537         $this->assertNull($record->onenum);
1538         $this->assertNull($record->onechar);
1539         $this->assertNull($record->onetext);
1540         $this->assertNull($record->onebinary);
1542         // Check zeros are set properly for all types
1543         $record = new stdClass();
1544         $record->oneint = 0;
1545         $record->onenum = 0;
1546         $recid = $DB->insert_record($tablename, $record);
1547         $record = $DB->get_record($tablename, array('id' => $recid));
1548         $this->assertEqual(0, $record->oneint);
1549         $this->assertEqual(0, $record->onenum);
1551         // Check booleans are set properly for all types
1552         $record = new stdClass();
1553         $record->oneint = true; // trues
1554         $record->onenum = true;
1555         $record->onechar = true;
1556         $record->onetext = true;
1557         $recid = $DB->insert_record($tablename, $record);
1558         $record = $DB->get_record($tablename, array('id' => $recid));
1559         $this->assertEqual(1, $record->oneint);
1560         $this->assertEqual(1, $record->onenum);
1561         $this->assertEqual(1, $record->onechar);
1562         $this->assertEqual(1, $record->onetext);
1564         $record = new stdClass();
1565         $record->oneint = false; // falses
1566         $record->onenum = false;
1567         $record->onechar = false;
1568         $record->onetext = false;
1569         $recid = $DB->insert_record($tablename, $record);
1570         $record = $DB->get_record($tablename, array('id' => $recid));
1571         $this->assertEqual(0, $record->oneint);
1572         $this->assertEqual(0, $record->onenum);
1573         $this->assertEqual(0, $record->onechar);
1574         $this->assertEqual(0, $record->onetext);
1576         // Check string data causes exception in numeric types
1577         $record = new stdClass();
1578         $record->oneint = 'onestring';
1579         $record->onenum = 0;
1580         try {
1581             $DB->insert_record($tablename, $record);
1582             $this->fail("Expecting an exception, none occurred");
1583         } catch (exception $e) {
1584             $this->assertTrue($e instanceof dml_exception);
1585         }
1586         $record = new stdClass();
1587         $record->oneint = 0;
1588         $record->onenum = 'onestring';
1589         try {
1590            $DB->insert_record($tablename, $record);
1591            $this->fail("Expecting an exception, none occurred");
1592         } catch (exception $e) {
1593             $this->assertTrue($e instanceof dml_exception);
1594         }
1596         // Check empty string data is stored as 0 in numeric datatypes
1597         $record = new stdClass();
1598         $record->oneint = ''; // empty string
1599         $record->onenum = 0;
1600         $recid = $DB->insert_record($tablename, $record);
1601         $record = $DB->get_record($tablename, array('id' => $recid));
1602         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
1604         $record = new stdClass();
1605         $record->oneint = 0;
1606         $record->onenum = ''; // empty string
1607         $recid = $DB->insert_record($tablename, $record);
1608         $record = $DB->get_record($tablename, array('id' => $recid));
1609         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
1611         // Check empty strings are set properly in string types
1612         $record = new stdClass();
1613         $record->oneint = 0;
1614         $record->onenum = 0;
1615         $record->onechar = '';
1616         $record->onetext = '';
1617         $recid = $DB->insert_record($tablename, $record);
1618         $record = $DB->get_record($tablename, array('id' => $recid));
1619         $this->assertTrue($record->onechar === '');
1620         $this->assertTrue($record->onetext === '');
1622         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1623         $record = new stdClass();
1624         $record->oneint = ((210.10 + 39.92) - 150.02);
1625         $record->onenum = ((210.10 + 39.92) - 150.02);
1626         $recid = $DB->insert_record($tablename, $record);
1627         $record = $DB->get_record($tablename, array('id' => $recid));
1628         $this->assertEqual(100, $record->oneint);
1629         $this->assertEqual(100, $record->onenum);
1631         // Check various quotes/backslashes combinations in string types
1632         $teststrings = array(
1633             'backslashes and quotes alone (even): "" \'\' \\\\',
1634             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1635             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1636             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1637         foreach ($teststrings as $teststring) {
1638             $record = new stdClass();
1639             $record->onechar = $teststring;
1640             $record->onetext = $teststring;
1641             $recid = $DB->insert_record($tablename, $record);
1642             $record = $DB->get_record($tablename, array('id' => $recid));
1643             $this->assertEqual($teststring, $record->onechar);
1644             $this->assertEqual($teststring, $record->onetext);
1645         }
1647         // Check LOBs in text/binary columns
1648         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
1649         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
1650         $record = new stdClass();
1651         $record->onetext = $clob;
1652         $record->onebinary = $blob;
1653         $recid = $DB->insert_record($tablename, $record);
1654         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1655         $record = $rs->current();
1656         $rs->close();
1657         $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
1658         $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
1660         // And "small" LOBs too, just in case
1661         $newclob = substr($clob, 0, 500);
1662         $newblob = substr($blob, 0, 250);
1663         $record = new stdClass();
1664         $record->onetext = $newclob;
1665         $record->onebinary = $newblob;
1666         $recid = $DB->insert_record($tablename, $record);
1667         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1668         $record = $rs->current();
1669         $rs->close();
1670         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
1671         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
1672         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
1674         // And "diagnostic" LOBs too, just in case
1675         $newclob = '\'"\\;/ěščřžýáíé';
1676         $newblob = '\'"\\;/ěščřžýáíé';
1677         $record = new stdClass();
1678         $record->onetext = $newclob;
1679         $record->onebinary = $newblob;
1680         $recid = $DB->insert_record($tablename, $record);
1681         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1682         $record = $rs->current();
1683         $rs->close();
1684         $this->assertIdentical($newclob, $record->onetext);
1685         $this->assertIdentical($newblob, $record->onebinary);
1686         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
1688         // test data is not modified
1689         $record = new stdClass();
1690         $record->id     = -1; // has to be ignored
1691         $record->course = 3;
1692         $record->lalala = 'lalal'; // unused
1693         $before = clone($record);
1694         $DB->insert_record($tablename, $record);
1695         $this->assertEqual($record, $before);
1697         // make sure the id is always increasing and never reuses the same id
1698         $id1 = $DB->insert_record($tablename, array('course' => 3));
1699         $id2 = $DB->insert_record($tablename, array('course' => 3));
1700         $this->assertTrue($id1 < $id2);
1701         $DB->delete_records($tablename, array('id'=>$id2));
1702         $id3 = $DB->insert_record($tablename, array('course' => 3));
1703         $this->assertTrue($id2 < $id3);
1704         $DB->delete_records($tablename, array());
1705         $id4 = $DB->insert_record($tablename, array('course' => 3));
1706         $this->assertTrue($id3 < $id4);
1707     }
1709     public function test_import_record() {
1710         // All the information in this test is fetched from DB by get_recordset() so we
1711         // have such method properly tested against nulls, empties and friends...
1713         $DB = $this->tdb;
1714         $dbman = $DB->get_manager();
1716         $table = $this->get_test_table();
1717         $tablename = $table->getName();
1719         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1720         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1721         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
1722         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1723         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1724         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1725         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1726         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1727         $dbman->create_table($table);
1729         $this->assertIdentical(1, $DB->insert_record($tablename, array('course' => 1), true));
1730         $record = $DB->get_record($tablename, array('course' => 1));
1731         $this->assertEqual(1, $record->id);
1732         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
1733         $this->assertEqual(200, $record->onenum);
1734         $this->assertIdentical('onestring', $record->onechar);
1735         $this->assertNull($record->onetext);
1736         $this->assertNull($record->onebinary);
1738         // ignore extra columns
1739         $record = (object)array('id'=>13, 'course'=>2, 'xxxx'=>788778);
1740         $before = clone($record);
1741         $this->assertIdentical(true, $DB->import_record($tablename, $record));
1742         $this->assertIdentical($record, $before);
1743         $records = $DB->get_records($tablename);
1744         $this->assertEqual(2, $records[13]->course);
1746         // Check nulls are set properly for all types
1747         $record = new stdClass();
1748         $record->id = 20;
1749         $record->oneint = null;
1750         $record->onenum = null;
1751         $record->onechar = null;
1752         $record->onetext = null;
1753         $record->onebinary = null;
1754         $this->assertTrue($DB->import_record($tablename, $record));
1755         $record = $DB->get_record($tablename, array('id' => 20));
1756         $this->assertEqual(0, $record->course);
1757         $this->assertNull($record->oneint);
1758         $this->assertNull($record->onenum);
1759         $this->assertNull($record->onechar);
1760         $this->assertNull($record->onetext);
1761         $this->assertNull($record->onebinary);
1763         // Check zeros are set properly for all types
1764         $record = new stdClass();
1765         $record->id = 23;
1766         $record->oneint = 0;
1767         $record->onenum = 0;
1768         $this->assertTrue($DB->import_record($tablename, $record));
1769         $record = $DB->get_record($tablename, array('id' => 23));
1770         $this->assertEqual(0, $record->oneint);
1771         $this->assertEqual(0, $record->onenum);
1773         // Check string data causes exception in numeric types
1774         $record = new stdClass();
1775         $record->id = 32;
1776         $record->oneint = 'onestring';
1777         $record->onenum = 0;
1778         try {
1779             $DB->import_record($tablename, $record);
1780             $this->fail("Expecting an exception, none occurred");
1781         } catch (exception $e) {
1782             $this->assertTrue($e instanceof dml_exception);
1783         }
1784         $record = new stdClass();
1785         $record->id = 35;
1786         $record->oneint = 0;
1787         $record->onenum = 'onestring';
1788         try {
1789            $DB->import_record($tablename, $record);
1790            $this->fail("Expecting an exception, none occurred");
1791         } catch (exception $e) {
1792             $this->assertTrue($e instanceof dml_exception);
1793         }
1795         // Check empty strings are set properly in string types
1796         $record = new stdClass();
1797         $record->id = 44;
1798         $record->oneint = 0;
1799         $record->onenum = 0;
1800         $record->onechar = '';
1801         $record->onetext = '';
1802         $this->assertTrue($DB->import_record($tablename, $record));
1803         $record = $DB->get_record($tablename, array('id' => 44));
1804         $this->assertTrue($record->onechar === '');
1805         $this->assertTrue($record->onetext === '');
1807         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1808         $record = new stdClass();
1809         $record->id = 47;
1810         $record->oneint = ((210.10 + 39.92) - 150.02);
1811         $record->onenum = ((210.10 + 39.92) - 150.02);
1812         $this->assertTrue($DB->import_record($tablename, $record));
1813         $record = $DB->get_record($tablename, array('id' => 47));
1814         $this->assertEqual(100, $record->oneint);
1815         $this->assertEqual(100, $record->onenum);
1817         // Check various quotes/backslashes combinations in string types
1818         $i = 50;
1819         $teststrings = array(
1820             'backslashes and quotes alone (even): "" \'\' \\\\',
1821             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1822             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1823             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1824         foreach ($teststrings as $teststring) {
1825             $record = new stdClass();
1826             $record->id = $i;
1827             $record->onechar = $teststring;
1828             $record->onetext = $teststring;
1829             $this->assertTrue($DB->import_record($tablename, $record));
1830             $record = $DB->get_record($tablename, array('id' => $i));
1831             $this->assertEqual($teststring, $record->onechar);
1832             $this->assertEqual($teststring, $record->onetext);
1833             $i = $i + 3;
1834         }
1836         // Check LOBs in text/binary columns
1837         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
1838         $record = new stdClass();
1839         $record->id = 70;
1840         $record->onetext = $clob;
1841         $record->onebinary = '';
1842         $this->assertTrue($DB->import_record($tablename, $record));
1843         $rs = $DB->get_recordset($tablename, array('id' => 70));
1844         $record = $rs->current();
1845         $rs->close();
1846         $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
1848         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
1849         $record = new stdClass();
1850         $record->id = 71;
1851         $record->onetext = '';
1852         $record->onebinary = $blob;
1853         $this->assertTrue($DB->import_record($tablename, $record));
1854         $rs = $DB->get_recordset($tablename, array('id' => 71));
1855         $record = $rs->current();
1856         $rs->close();
1857         $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
1859         // And "small" LOBs too, just in case
1860         $newclob = substr($clob, 0, 500);
1861         $newblob = substr($blob, 0, 250);
1862         $record = new stdClass();
1863         $record->id = 73;
1864         $record->onetext = $newclob;
1865         $record->onebinary = $newblob;
1866         $this->assertTrue($DB->import_record($tablename, $record));
1867         $rs = $DB->get_recordset($tablename, array('id' => 73));
1868         $record = $rs->current();
1869         $rs->close();
1870         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
1871         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
1872         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
1873     }
1875     public function test_update_record_raw() {
1876         $DB = $this->tdb;
1877         $dbman = $DB->get_manager();
1879         $table = $this->get_test_table();
1880         $tablename = $table->getName();
1882         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1883         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1884         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1885         $dbman->create_table($table);
1887         $DB->insert_record($tablename, array('course' => 1));
1888         $DB->insert_record($tablename, array('course' => 3));
1890         $record = $DB->get_record($tablename, array('course' => 1));
1891         $record->course = 2;
1892         $this->assertTrue($DB->update_record_raw($tablename, $record));
1893         $this->assertEqual(0, $DB->count_records($tablename, array('course' => 1)));
1894         $this->assertEqual(1, $DB->count_records($tablename, array('course' => 2)));
1895         $this->assertEqual(1, $DB->count_records($tablename, array('course' => 3)));
1897         $record = $DB->get_record($tablename, array('course' => 1));
1898         $record->xxxxx = 2;
1899         try {
1900            $DB->update_record_raw($tablename, $record);
1901            $this->fail("Expecting an exception, none occurred");
1902         } catch (Exception $e) {
1903             $this->assertTrue($e instanceof coding_exception);
1904         }
1906         $record = $DB->get_record($tablename, array('course' => 3));
1907         unset($record->id);
1908         try {
1909            $DB->update_record_raw($tablename, $record);
1910            $this->fail("Expecting an exception, none occurred");
1911         } catch (Exception $e) {
1912             $this->assertTrue($e instanceof coding_exception);
1913         }
1914     }
1916     public function test_update_record() {
1918         // All the information in this test is fetched from DB by get_record() so we
1919         // have such method properly tested against nulls, empties and friends...
1921         $DB = $this->tdb;
1922         $dbman = $DB->get_manager();
1924         $table = $this->get_test_table();
1925         $tablename = $table->getName();
1927         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1928         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1929         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
1930         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1931         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1932         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1933         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1934         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1935         $dbman->create_table($table);
1937         $DB->insert_record($tablename, array('course' => 1));
1938         $record = $DB->get_record($tablename, array('course' => 1));
1939         $record->course = 2;
1941         $this->assertTrue($DB->update_record($tablename, $record));
1942         $this->assertFalse($record = $DB->get_record($tablename, array('course' => 1)));
1943         $this->assertTrue($record = $DB->get_record($tablename, array('course' => 2)));
1944         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
1945         $this->assertEqual(200, $record->onenum);
1946         $this->assertEqual('onestring', $record->onechar);
1947         $this->assertNull($record->onetext);
1948         $this->assertNull($record->onebinary);
1950         // Check nulls are set properly for all types
1951         $record->oneint = null;
1952         $record->onenum = null;
1953         $record->onechar = null;
1954         $record->onetext = null;
1955         $record->onebinary = null;
1956         $DB->update_record($tablename, $record);
1957         $record = $DB->get_record($tablename, array('course' => 2));
1958         $this->assertNull($record->oneint);
1959         $this->assertNull($record->onenum);
1960         $this->assertNull($record->onechar);
1961         $this->assertNull($record->onetext);
1962         $this->assertNull($record->onebinary);
1964         // Check zeros are set properly for all types
1965         $record->oneint = 0;
1966         $record->onenum = 0;
1967         $DB->update_record($tablename, $record);
1968         $record = $DB->get_record($tablename, array('course' => 2));
1969         $this->assertEqual(0, $record->oneint);
1970         $this->assertEqual(0, $record->onenum);
1972         // Check booleans are set properly for all types
1973         $record->oneint = true; // trues
1974         $record->onenum = true;
1975         $record->onechar = true;
1976         $record->onetext = true;
1977         $DB->update_record($tablename, $record);
1978         $record = $DB->get_record($tablename, array('course' => 2));
1979         $this->assertEqual(1, $record->oneint);
1980         $this->assertEqual(1, $record->onenum);
1981         $this->assertEqual(1, $record->onechar);
1982         $this->assertEqual(1, $record->onetext);
1984         $record->oneint = false; // falses
1985         $record->onenum = false;
1986         $record->onechar = false;
1987         $record->onetext = false;
1988         $DB->update_record($tablename, $record);
1989         $record = $DB->get_record($tablename, array('course' => 2));
1990         $this->assertEqual(0, $record->oneint);
1991         $this->assertEqual(0, $record->onenum);
1992         $this->assertEqual(0, $record->onechar);
1993         $this->assertEqual(0, $record->onetext);
1995         // Check string data causes exception in numeric types
1996         $record->oneint = 'onestring';
1997         $record->onenum = 0;
1998         try {
1999             $DB->update_record($tablename, $record);
2000             $this->fail("Expecting an exception, none occurred");
2001         } catch (exception $e) {
2002             $this->assertTrue($e instanceof dml_exception);
2003         }
2004         $record->oneint = 0;
2005         $record->onenum = 'onestring';
2006         try {
2007             $DB->update_record($tablename, $record);
2008             $this->fail("Expecting an exception, none occurred");
2009         } catch (exception $e) {
2010             $this->assertTrue($e instanceof dml_exception);
2011         }
2013         // Check empty string data is stored as 0 in numeric datatypes
2014         $record->oneint = ''; // empty string
2015         $record->onenum = 0;
2016         $DB->update_record($tablename, $record);
2017         $record = $DB->get_record($tablename, array('course' => 2));
2018         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
2020         $record->oneint = 0;
2021         $record->onenum = ''; // empty string
2022         $DB->update_record($tablename, $record);
2023         $record = $DB->get_record($tablename, array('course' => 2));
2024         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
2026         // Check empty strings are set properly in string types
2027         $record->oneint = 0;
2028         $record->onenum = 0;
2029         $record->onechar = '';
2030         $record->onetext = '';
2031         $DB->update_record($tablename, $record);
2032         $record = $DB->get_record($tablename, array('course' => 2));
2033         $this->assertTrue($record->onechar === '');
2034         $this->assertTrue($record->onetext === '');
2036         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
2037         $record->oneint = ((210.10 + 39.92) - 150.02);
2038         $record->onenum = ((210.10 + 39.92) - 150.02);
2039         $DB->update_record($tablename, $record);
2040         $record = $DB->get_record($tablename, array('course' => 2));
2041         $this->assertEqual(100, $record->oneint);
2042         $this->assertEqual(100, $record->onenum);
2044         // Check various quotes/backslashes combinations in string types
2045         $teststrings = array(
2046             'backslashes and quotes alone (even): "" \'\' \\\\',
2047             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2048             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2049             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2050         foreach ($teststrings as $teststring) {
2051             $record->onechar = $teststring;
2052             $record->onetext = $teststring;
2053             $DB->update_record($tablename, $record);
2054             $record = $DB->get_record($tablename, array('course' => 2));
2055             $this->assertEqual($teststring, $record->onechar);
2056             $this->assertEqual($teststring, $record->onetext);
2057         }
2059         // Check LOBs in text/binary columns
2060         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
2061         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
2062         $record->onetext = $clob;
2063         $record->onebinary = $blob;
2064         $DB->update_record($tablename, $record);
2065         $record = $DB->get_record($tablename, array('course' => 2));
2066         $this->assertEqual($clob, $record->onetext, 'Test CLOB update (full contents output disabled)');
2067         $this->assertEqual($blob, $record->onebinary, 'Test BLOB update (full contents output disabled)');
2069         // And "small" LOBs too, just in case
2070         $newclob = substr($clob, 0, 500);
2071         $newblob = substr($blob, 0, 250);
2072         $record->onetext = $newclob;
2073         $record->onebinary = $newblob;
2074         $DB->update_record($tablename, $record);
2075         $record = $DB->get_record($tablename, array('course' => 2));
2076         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB update (full contents output disabled)');
2077         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB update (full contents output disabled)');
2079     }
2081     public function test_set_field() {
2082         $DB = $this->tdb;
2083         $dbman = $DB->get_manager();
2085         $table = $this->get_test_table();
2086         $tablename = $table->getName();
2088         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2089         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2090         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
2091         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2092         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2093         $dbman->create_table($table);
2095         // simple set_field
2096         $id1 = $DB->insert_record($tablename, array('course' => 1));
2097         $id2 = $DB->insert_record($tablename, array('course' => 1));
2098         $id3 = $DB->insert_record($tablename, array('course' => 3));
2099         $this->assertTrue($DB->set_field($tablename, 'course', 2, array('id' => $id1)));
2100         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => $id1)));
2101         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
2102         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2103         $DB->delete_records($tablename, array());
2105         // multiple fields affected
2106         $id1 = $DB->insert_record($tablename, array('course' => 1));
2107         $id2 = $DB->insert_record($tablename, array('course' => 1));
2108         $id3 = $DB->insert_record($tablename, array('course' => 3));
2109         $DB->set_field($tablename, 'course', '5', array('course' => 1));
2110         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
2111         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
2112         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2113         $DB->delete_records($tablename, array());
2115         // no field affected
2116         $id1 = $DB->insert_record($tablename, array('course' => 1));
2117         $id2 = $DB->insert_record($tablename, array('course' => 1));
2118         $id3 = $DB->insert_record($tablename, array('course' => 3));
2119         $DB->set_field($tablename, 'course', '5', array('course' => 0));
2120         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id1)));
2121         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
2122         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2123         $DB->delete_records($tablename, array());
2125         // all fields - no condition
2126         $id1 = $DB->insert_record($tablename, array('course' => 1));
2127         $id2 = $DB->insert_record($tablename, array('course' => 1));
2128         $id3 = $DB->insert_record($tablename, array('course' => 3));
2129         $DB->set_field($tablename, 'course', 5, array());
2130         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
2131         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
2132         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id3)));
2134         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2135         $conditions = array('onetext' => '1');
2136         try {
2137             $DB->set_field($tablename, 'onechar', 'frog', $conditions);
2138             $this->fail('An Exception is missing, expected due to equating of text fields');
2139         } catch (exception $e) {
2140             $this->assertTrue($e instanceof dml_exception);
2141             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2142         }
2144         // Note: All the nulls, booleans, empties, quoted and backslashes tests
2145         // go to set_field_select() because set_field() is just one wrapper over it
2146     }
2148     public function test_set_field_select() {
2150         // All the information in this test is fetched from DB by get_field() so we
2151         // have such method properly tested against nulls, empties and friends...
2153         $DB = $this->tdb;
2154         $dbman = $DB->get_manager();
2156         $table = $this->get_test_table();
2157         $tablename = $table->getName();
2159         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2160         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2161         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null);
2162         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null);
2163         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
2164         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2165         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2166         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2167         $dbman->create_table($table);
2169         $DB->insert_record($tablename, array('course' => 1));
2171         $this->assertTrue($DB->set_field_select($tablename, 'course', 2, 'id = ?', array(1)));
2172         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => 1)));
2174         // Check nulls are set properly for all types
2175         $DB->set_field_select($tablename, 'oneint', null, 'id = ?', array(1)); // trues
2176         $DB->set_field_select($tablename, 'onenum', null, 'id = ?', array(1));
2177         $DB->set_field_select($tablename, 'onechar', null, 'id = ?', array(1));
2178         $DB->set_field_select($tablename, 'onetext', null, 'id = ?', array(1));
2179         $DB->set_field_select($tablename, 'onebinary', null, 'id = ?', array(1));
2180         $this->assertNull($DB->get_field($tablename, 'oneint', array('id' => 1)));
2181         $this->assertNull($DB->get_field($tablename, 'onenum', array('id' => 1)));
2182         $this->assertNull($DB->get_field($tablename, 'onechar', array('id' => 1)));
2183         $this->assertNull($DB->get_field($tablename, 'onetext', array('id' => 1)));
2184         $this->assertNull($DB->get_field($tablename, 'onebinary', array('id' => 1)));
2186         // Check zeros are set properly for all types
2187         $DB->set_field_select($tablename, 'oneint', 0, 'id = ?', array(1));
2188         $DB->set_field_select($tablename, 'onenum', 0, 'id = ?', array(1));
2189         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2190         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2192         // Check booleans are set properly for all types
2193         $DB->set_field_select($tablename, 'oneint', true, 'id = ?', array(1)); // trues
2194         $DB->set_field_select($tablename, 'onenum', true, 'id = ?', array(1));
2195         $DB->set_field_select($tablename, 'onechar', true, 'id = ?', array(1));
2196         $DB->set_field_select($tablename, 'onetext', true, 'id = ?', array(1));
2197         $this->assertEqual(1, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2198         $this->assertEqual(1, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2199         $this->assertEqual(1, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2200         $this->assertEqual(1, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2202         $DB->set_field_select($tablename, 'oneint', false, 'id = ?', array(1)); // falses
2203         $DB->set_field_select($tablename, 'onenum', false, 'id = ?', array(1));
2204         $DB->set_field_select($tablename, 'onechar', false, 'id = ?', array(1));
2205         $DB->set_field_select($tablename, 'onetext', false, 'id = ?', array(1));
2206         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2207         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2208         $this->assertEqual(0, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2209         $this->assertEqual(0, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2211         // Check string data causes exception in numeric types
2212         try {
2213             $DB->set_field_select($tablename, 'oneint', 'onestring', 'id = ?', array(1));
2214             $this->fail("Expecting an exception, none occurred");
2215         } catch (exception $e) {
2216             $this->assertTrue($e instanceof dml_exception);
2217         }
2218         try {
2219             $DB->set_field_select($tablename, 'onenum', 'onestring', 'id = ?', array(1));
2220             $this->fail("Expecting an exception, none occurred");
2221         } catch (exception $e) {
2222             $this->assertTrue($e instanceof dml_exception);
2223         }
2225         // Check empty string data is stored as 0 in numeric datatypes
2226         $DB->set_field_select($tablename, 'oneint', '', 'id = ?', array(1));
2227         $field = $DB->get_field($tablename, 'oneint', array('id' => 1));
2228         $this->assertTrue(is_numeric($field) && $field == 0);
2230         $DB->set_field_select($tablename, 'onenum', '', 'id = ?', array(1));
2231         $field = $DB->get_field($tablename, 'onenum', array('id' => 1));
2232         $this->assertTrue(is_numeric($field) && $field == 0);
2234         // Check empty strings are set properly in string types
2235         $DB->set_field_select($tablename, 'onechar', '', 'id = ?', array(1));
2236         $DB->set_field_select($tablename, 'onetext', '', 'id = ?', array(1));
2237         $this->assertTrue($DB->get_field($tablename, 'onechar', array('id' => 1)) === '');
2238         $this->assertTrue($DB->get_field($tablename, 'onetext', array('id' => 1)) === '');
2240         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
2241         $DB->set_field_select($tablename, 'oneint', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
2242         $DB->set_field_select($tablename, 'onenum', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
2243         $this->assertEqual(100, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2244         $this->assertEqual(100, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2246         // Check various quotes/backslashes combinations in string types
2247         $teststrings = array(
2248             'backslashes and quotes alone (even): "" \'\' \\\\',
2249             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2250             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2251             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2252         foreach ($teststrings as $teststring) {
2253             $DB->set_field_select($tablename, 'onechar', $teststring, 'id = ?', array(1));
2254             $DB->set_field_select($tablename, 'onetext', $teststring, 'id = ?', array(1));
2255             $this->assertEqual($teststring, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2256             $this->assertEqual($teststring, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2257         }
2259         // Check LOBs in text/binary columns
2260         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
2261         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
2262         $DB->set_field_select($tablename, 'onetext', $clob, 'id = ?', array(1));
2263         $DB->set_field_select($tablename, 'onebinary', $blob, 'id = ?', array(1));
2264         $this->assertEqual($clob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test CLOB set_field (full contents output disabled)');
2265         $this->assertEqual($blob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test BLOB set_field (full contents output disabled)');
2267         // And "small" LOBs too, just in case
2268         $newclob = substr($clob, 0, 500);
2269         $newblob = substr($blob, 0, 250);
2270         $DB->set_field_select($tablename, 'onetext', $newclob, 'id = ?', array(1));
2271         $DB->set_field_select($tablename, 'onebinary', $newblob, 'id = ?', array(1));
2272         $this->assertEqual($newclob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test "small" CLOB set_field (full contents output disabled)');
2273         $this->assertEqual($newblob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test "small" BLOB set_field (full contents output disabled)');
2275         // This is the failure from MDL-24863. This was giving an error on MSSQL,
2276         // which converts the '1' to an integer, which cannot then be compared with
2277         // onetext cast to a varchar. This should be fixed and working now.
2278         $newchar = 'frog';
2279         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2280         $params = array('onetext' => '1');
2281         try {
2282             $DB->set_field_select($tablename, 'onechar', $newchar, $DB->sql_compare_text('onetext') . ' = ?', $params);
2283             $this->assertTrue(true, 'No exceptions thrown with numerical text param comparison for text field.');
2284         } catch (dml_exception $e) {
2285             $this->assertFalse(true, 'We have an unexpected exception.');
2286             throw $e;
2287         }
2290     }
2292     public function test_count_records() {
2293         $DB = $this->tdb;
2295         $dbman = $DB->get_manager();
2297         $table = $this->get_test_table();
2298         $tablename = $table->getName();
2300         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2301         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2302         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2303         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2304         $dbman->create_table($table);
2306         $this->assertEqual(0, $DB->count_records($tablename));
2308         $DB->insert_record($tablename, array('course' => 3));
2309         $DB->insert_record($tablename, array('course' => 4));
2310         $DB->insert_record($tablename, array('course' => 5));
2312         $this->assertEqual(3, $DB->count_records($tablename));
2314         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2315         $conditions = array('onetext' => '1');
2316         try {
2317             $DB->count_records($tablename, $conditions);
2318             $this->fail('An Exception is missing, expected due to equating of text fields');
2319         } catch (exception $e) {
2320             $this->assertTrue($e instanceof dml_exception);
2321             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2322         }
2323     }
2325     public function test_count_records_select() {
2326         $DB = $this->tdb;
2328         $dbman = $DB->get_manager();
2330         $table = $this->get_test_table();
2331         $tablename = $table->getName();
2333         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2334         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2335         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2336         $dbman->create_table($table);
2338         $this->assertEqual(0, $DB->count_records($tablename));
2340         $DB->insert_record($tablename, array('course' => 3));
2341         $DB->insert_record($tablename, array('course' => 4));
2342         $DB->insert_record($tablename, array('course' => 5));
2344         $this->assertEqual(2, $DB->count_records_select($tablename, 'course > ?', array(3)));
2345     }
2347     public function test_count_records_sql() {
2348         $DB = $this->tdb;
2349         $dbman = $DB->get_manager();
2351         $table = $this->get_test_table();
2352         $tablename = $table->getName();
2354         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2355         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2356         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2357         $dbman->create_table($table);
2359         $this->assertEqual(0, $DB->count_records($tablename));
2361         $DB->insert_record($tablename, array('course' => 3));
2362         $DB->insert_record($tablename, array('course' => 4));
2363         $DB->insert_record($tablename, array('course' => 5));
2365         $this->assertEqual(2, $DB->count_records_sql("SELECT COUNT(*) FROM {{$tablename}} WHERE course > ?", array(3)));
2366     }
2368     public function test_record_exists() {
2369         $DB = $this->tdb;
2370         $dbman = $DB->get_manager();
2372         $table = $this->get_test_table();
2373         $tablename = $table->getName();
2375         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2376         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2377         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2378         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2379         $dbman->create_table($table);
2381         $this->assertEqual(0, $DB->count_records($tablename));
2383         $this->assertFalse($DB->record_exists($tablename, array('course' => 3)));
2384         $DB->insert_record($tablename, array('course' => 3));
2386         $this->assertTrue($DB->record_exists($tablename, array('course' => 3)));
2389         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2390         $conditions = array('onetext' => '1');
2391         try {
2392             $DB->record_exists($tablename, $conditions);
2393             $this->fail('An Exception is missing, expected due to equating of text fields');
2394         } catch (exception $e) {
2395             $this->assertTrue($e instanceof dml_exception);
2396             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2397         }
2398     }
2400     public function test_record_exists_select() {
2401         $DB = $this->tdb;
2402         $dbman = $DB->get_manager();
2404         $table = $this->get_test_table();
2405         $tablename = $table->getName();
2407         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2408         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2409         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2410         $dbman->create_table($table);
2412         $this->assertEqual(0, $DB->count_records($tablename));
2414         $this->assertFalse($DB->record_exists_select($tablename, "course = ?", array(3)));
2415         $DB->insert_record($tablename, array('course' => 3));
2417         $this->assertTrue($DB->record_exists_select($tablename, "course = ?", array(3)));
2418     }
2420     public function test_record_exists_sql() {
2421         $DB = $this->tdb;
2422         $dbman = $DB->get_manager();
2424         $table = $this->get_test_table();
2425         $tablename = $table->getName();
2427         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2428         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2429         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2430         $dbman->create_table($table);
2432         $this->assertEqual(0, $DB->count_records($tablename));
2434         $this->assertFalse($DB->record_exists_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3)));
2435         $DB->insert_record($tablename, array('course' => 3));
2437         $this->assertTrue($DB->record_exists_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3)));
2438     }
2440     public function test_recordset_locks_delete() {
2441         $DB = $this->tdb;
2442         $dbman = $DB->get_manager();
2444         //Setup
2445         $table = $this->get_test_table();
2446         $tablename = $table->getName();
2448         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2449         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2450         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2451         $dbman->create_table($table);
2453         $DB->insert_record($tablename, array('course' => 1));
2454         $DB->insert_record($tablename, array('course' => 2));
2455         $DB->insert_record($tablename, array('course' => 3));
2456         $DB->insert_record($tablename, array('course' => 4));
2457         $DB->insert_record($tablename, array('course' => 5));
2458         $DB->insert_record($tablename, array('course' => 6));
2460         // Test against db write locking while on an open recordset
2461         $rs = $DB->get_recordset($tablename, array(), null, 'course', 2, 2); // get courses = {3,4}
2462         foreach ($rs as $record) {
2463             $cid = $record->course;
2464             $DB->delete_records($tablename, array('course' => $cid));
2465             $this->assertFalse($DB->record_exists($tablename, array('course' => $cid)));
2466         }
2467         $rs->close();
2469         $this->assertEqual(4, $DB->count_records($tablename, array()));
2470     }
2472     public function test_recordset_locks_update() {
2473         $DB = $this->tdb;
2474         $dbman = $DB->get_manager();
2476         //Setup
2477         $table = $this->get_test_table();
2478         $tablename = $table->getName();
2480         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2481         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2482         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2483         $dbman->create_table($table);
2485         $DB->insert_record($tablename, array('course' => 1));
2486         $DB->insert_record($tablename, array('course' => 2));
2487         $DB->insert_record($tablename, array('course' => 3));
2488         $DB->insert_record($tablename, array('course' => 4));
2489         $DB->insert_record($tablename, array('course' => 5));
2490         $DB->insert_record($tablename, array('course' => 6));
2492         // Test against db write locking while on an open recordset
2493         $rs = $DB->get_recordset($tablename, array(), null, 'course', 2, 2); // get courses = {3,4}
2494         foreach ($rs as $record) {
2495             $cid = $record->course;
2496             $DB->set_field($tablename, 'course', 10, array('course' => $cid));
2497             $this->assertFalse($DB->record_exists($tablename, array('course' => $cid)));
2498         }
2499         $rs->close();
2501         $this->assertEqual(2, $DB->count_records($tablename, array('course' => 10)));
2502     }
2504     public function test_delete_records() {
2505         $DB = $this->tdb;
2506         $dbman = $DB->get_manager();
2508         $table = $this->get_test_table();
2509         $tablename = $table->getName();
2511         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2512         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2513         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2514         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2515         $dbman->create_table($table);
2517         $DB->insert_record($tablename, array('course' => 3));
2518         $DB->insert_record($tablename, array('course' => 2));
2519         $DB->insert_record($tablename, array('course' => 2));
2521         // Delete all records
2522         $this->assertTrue($DB->delete_records($tablename));
2523         $this->assertEqual(0, $DB->count_records($tablename));
2525         // Delete subset of records
2526         $DB->insert_record($tablename, array('course' => 3));
2527         $DB->insert_record($tablename, array('course' => 2));
2528         $DB->insert_record($tablename, array('course' => 2));
2530         $this->assertTrue($DB->delete_records($tablename, array('course' => 2)));
2531         $this->assertEqual(1, $DB->count_records($tablename));
2533         // delete all
2534         $this->assertTrue($DB->delete_records($tablename, array()));
2535         $this->assertEqual(0, $DB->count_records($tablename));
2537         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2538         $conditions = array('onetext'=>'1');
2539         try {
2540             $DB->delete_records($tablename, $conditions);
2541             $this->fail('An Exception is missing, expected due to equating of text fields');
2542         } catch (exception $e) {
2543             $this->assertTrue($e instanceof dml_exception);
2544             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2545         }
2547         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2548         $conditions = array('onetext' => 1);
2549         try {
2550             $DB->delete_records($tablename, $conditions);
2551             $this->fail('An Exception is missing, expected due to equating of text fields');
2552         } catch (exception $e) {
2553             $this->assertTrue($e instanceof dml_exception);
2554             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2555         }
2556     }
2558     public function test_delete_records_select() {
2559         $DB = $this->tdb;
2560         $dbman = $DB->get_manager();
2562         $table = $this->get_test_table();
2563         $tablename = $table->getName();
2565         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2566         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2567         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2568         $dbman->create_table($table);
2570         $DB->insert_record($tablename, array('course' => 3));
2571         $DB->insert_record($tablename, array('course' => 2));
2572         $DB->insert_record($tablename, array('course' => 2));
2574         $this->assertTrue($DB->delete_records_select($tablename, 'course = ?', array(2)));
2575         $this->assertEqual(1, $DB->count_records($tablename));
2576     }
2578     public function test_delete_records_list() {
2579         $DB = $this->tdb;
2580         $dbman = $DB->get_manager();
2582         $table = $this->get_test_table();
2583         $tablename = $table->getName();
2585         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2586         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2587         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2588         $dbman->create_table($table);
2590         $DB->insert_record($tablename, array('course' => 1));
2591         $DB->insert_record($tablename, array('course' => 2));
2592         $DB->insert_record($tablename, array('course' => 3));
2594         $this->assertTrue($DB->delete_records_list($tablename, 'course', array(2, 3)));
2595         $this->assertEqual(1, $DB->count_records($tablename));
2597         $this->assertTrue($DB->delete_records_list($tablename, 'course', array())); /// Must delete 0 rows without conditions. MDL-17645
2598         $this->assertEqual(1, $DB->count_records($tablename));
2599     }
2601     function test_sql_null_from_clause() {
2602         $DB = $this->tdb;
2603         $sql = "SELECT 1 AS id ".$DB->sql_null_from_clause();
2604         $this->assertEqual($DB->get_field_sql($sql), 1);
2605     }
2607     function test_sql_bitand() {
2608         $DB = $this->tdb;
2609         $dbman = $DB->get_manager();
2611         $table = $this->get_test_table();
2612         $tablename = $table->getName();
2614         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2615         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2616         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2617         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2618         $dbman->create_table($table);
2620         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
2622         $sql = "SELECT ".$DB->sql_bitand(10, 3)." AS res ".$DB->sql_null_from_clause();
2623         $this->assertEqual($DB->get_field_sql($sql), 2);
2625         $sql = "SELECT id, ".$DB->sql_bitand('col1', 'col2')." AS res FROM {{$tablename}}";
2626         $result = $DB->get_records_sql($sql);
2627         $this->assertEqual(count($result), 1);
2628         $this->assertEqual(reset($result)->res, 2);
2630         $sql = "SELECT id, ".$DB->sql_bitand('col1', '?')." AS res FROM {{$tablename}}";
2631         $result = $DB->get_records_sql($sql, array(10));
2632         $this->assertEqual(count($result), 1);
2633         $this->assertEqual(reset($result)->res, 2);
2634     }
2636     function test_sql_bitnot() {
2637         $DB = $this->tdb;
2639         $not = $DB->sql_bitnot(2);
2640         $notlimited = $DB->sql_bitand($not, 7); // might be positive or negative number which can not fit into PHP INT!
2642         $sql = "SELECT $notlimited AS res ".$DB->sql_null_from_clause();
2643         $this->assertEqual($DB->get_field_sql($sql), 5);
2644     }
2646     function test_sql_bitor() {
2647         $DB = $this->tdb;
2648         $dbman = $DB->get_manager();
2650         $table = $this->get_test_table();
2651         $tablename = $table->getName();
2653         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2654         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2655         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2656         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2657         $dbman->create_table($table);
2659         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
2661         $sql = "SELECT ".$DB->sql_bitor(10, 3)." AS res ".$DB->sql_null_from_clause();
2662         $this->assertEqual($DB->get_field_sql($sql), 11);
2664         $sql = "SELECT id, ".$DB->sql_bitor('col1', 'col2')." AS res FROM {{$tablename}}";
2665         $result = $DB->get_records_sql($sql);
2666         $this->assertEqual(count($result), 1);
2667         $this->assertEqual(reset($result)->res, 11);
2669         $sql = "SELECT id, ".$DB->sql_bitor('col1', '?')." AS res FROM {{$tablename}}";
2670         $result = $DB->get_records_sql($sql, array(10));
2671         $this->assertEqual(count($result), 1);
2672         $this->assertEqual(reset($result)->res, 11);
2673     }
2675     function test_sql_bitxor() {
2676         $DB = $this->tdb;
2677         $dbman = $DB->get_manager();
2679         $table = $this->get_test_table();
2680         $tablename = $table->getName();
2682         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2683         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2684         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2685         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2686         $dbman->create_table($table);
2688         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
2690         $sql = "SELECT ".$DB->sql_bitxor(10, 3)." AS res ".$DB->sql_null_from_clause();
2691         $this->assertEqual($DB->get_field_sql($sql), 9);
2693         $sql = "SELECT id, ".$DB->sql_bitxor('col1', 'col2')." AS res FROM {{$tablename}}";
2694         $result = $DB->get_records_sql($sql);
2695         $this->assertEqual(count($result), 1);
2696         $this->assertEqual(reset($result)->res, 9);
2698         $sql = "SELECT id, ".$DB->sql_bitxor('col1', '?')." AS res FROM {{$tablename}}";
2699         $result = $DB->get_records_sql($sql, array(10));
2700         $this->assertEqual(count($result), 1);
2701         $this->assertEqual(reset($result)->res, 9);
2702     }
2704     function test_sql_modulo() {
2705         $DB = $this->tdb;
2706         $sql = "SELECT ".$DB->sql_modulo(10, 7)." AS res ".$DB->sql_null_from_clause();
2707         $this->assertEqual($DB->get_field_sql($sql), 3);
2708     }
2710     function test_sql_ceil() {
2711         $DB = $this->tdb;
2712         $sql = "SELECT ".$DB->sql_ceil(665.666)." AS res ".$DB->sql_null_from_clause();
2713         $this->assertEqual($DB->get_field_sql($sql), 666);
2714     }
2716     function test_cast_char2int() {
2717         $DB = $this->tdb;
2718         $dbman = $DB->get_manager();
2720         $table1 = $this->get_test_table("1");
2721         $tablename1 = $table1->getName();
2723         $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2724         $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2725         $table1->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
2726         $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2727         $dbman->create_table($table1);
2729         $DB->insert_record($tablename1, array('name'=>'0100', 'nametext'=>'0200'));
2730         $DB->insert_record($tablename1, array('name'=>'10',   'nametext'=>'20'));
2732         $table2 = $this->get_test_table("2");
2733         $tablename2 = $table2->getName();
2734         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2735         $table2->add_field('res', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2736         $table2->add_field('restext', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2737         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2738         $dbman->create_table($table2);
2740         $DB->insert_record($tablename2, array('res'=>100, 'restext'=>200));
2742         // casting varchar field
2743         $sql = "SELECT *
2744                   FROM {".$tablename1."} t1
2745                   JOIN {".$tablename2."} t2 ON ".$DB->sql_cast_char2int("t1.name")." = t2.res ";
2746         $records = $DB->get_records_sql($sql);
2747         $this->assertEqual(count($records), 1);
2748         // also test them in order clauses
2749         $sql = "SELECT * FROM {{$tablename1}} ORDER BY ".$DB->sql_cast_char2int('name');
2750         $records = $DB->get_records_sql($sql);
2751         $this->assertEqual(count($records), 2);
2752         $this->assertEqual(reset($records)->name, '10');
2753         $this->assertEqual(next($records)->name, '0100');
2755         // casting text field
2756         $sql = "SELECT *
2757                   FROM {".$tablename1."} t1
2758                   JOIN {".$tablename2."} t2 ON ".$DB->sql_cast_char2int("t1.nametext", true)." = t2.restext ";
2759         $records = $DB->get_records_sql($sql);
2760         $this->assertEqual(count($records), 1);
2761         // also test them in order clauses
2762         $sql = "SELECT * FROM {{$tablename1}} ORDER BY ".$DB->sql_cast_char2int('nametext', true);
2763         $records = $DB->get_records_sql($sql);
2764         $this->assertEqual(count($records), 2);
2765         $this->assertEqual(reset($records)->nametext, '20');
2766         $this->assertEqual(next($records)->nametext, '0200');
2767     }
2769     function test_cast_char2real() {
2770         $DB = $this->tdb;
2771         $dbman = $DB->get_manager();
2773         $table = $this->get_test_table();
2774         $tablename = $table->getName();
2776         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2777         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2778         $table->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
2779         $table->add_field('res', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null);
2780         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2781         $dbman->create_table($table);
2783         $DB->insert_record($tablename, array('name'=>'10.10', 'nametext'=>'10.10', 'res'=>5.1));
2784         $DB->insert_record($tablename, array('name'=>'91.10', 'nametext'=>'91.10', 'res'=>666));
2785         $DB->insert_record($tablename, array('name'=>'011.10','nametext'=>'011.10','res'=>10.1));
2787         // casting varchar field
2788         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_cast_char2real('name')." > res";
2789         $records = $DB->get_records_sql($sql);
2790         $this->assertEqual(count($records), 2);
2791         // also test them in order clauses
2792         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_cast_char2real('name');
2793         $records = $DB->get_records_sql($sql);
2794         $this->assertEqual(count($records), 3);
2795         $this->assertEqual(reset($records)->name, '10.10');
2796         $this->assertEqual(next($records)->name, '011.10');
2797         $this->assertEqual(next($records)->name, '91.10');
2799         // casting text field
2800         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_cast_char2real('nametext', true)." > res";
2801         $records = $DB->get_records_sql($sql);
2802         $this->assertEqual(count($records), 2);
2803         // also test them in order clauses
2804         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_cast_char2real('nametext', true);
2805         $records = $DB->get_records_sql($sql);
2806         $this->assertEqual(count($records), 3);
2807         $this->assertEqual(reset($records)->nametext, '10.10');
2808         $this->assertEqual(next($records)->nametext, '011.10');
2809         $this->assertEqual(next($records)->nametext, '91.10');
2810     }
2812     function sql_compare_text() {
2813         $DB = $this->tdb;
2814         $dbman = $DB->get_manager();
2816         $table = $this->get_test_table();
2817         $tablename = $table->getName();
2819         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2820         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2821         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2822         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2823         $dbman->create_table($table);
2825         $DB->insert_record($tablename, array('name'=>'abcd',   'description'=>'abcd'));
2826         $DB->insert_record($tablename, array('name'=>'abcdef', 'description'=>'bbcdef'));
2827         $DB->insert_record($tablename, array('name'=>'aaaabb', 'description'=>'aaaacccccccccccccccccc'));
2829         $sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description');
2830         $records = $DB->get_records_sql($sql);
2831         $this->assertEqual(count($records), 1);
2833         $sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description', 4);
2834         $records = $DB->get_records_sql($sql);
2835         $this->assertEqual(count($records), 2);
2836     }
2838     function test_unique_index_collation_trouble() {
2839         // note: this is a work in progress, we should probably move this to ddl test
2841         $DB = $this->tdb;
2842         $dbman = $DB->get_manager();
2844         $table = $this->get_test_table();
2845         $tablename = $table->getName();
2847         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2848         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2849         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2850         $table->add_index('name', XMLDB_INDEX_UNIQUE, array('name'));
2851         $dbman->create_table($table);
2853         $DB->insert_record($tablename, array('name'=>'aaa'));
2855         try {
2856             $DB->insert_record($tablename, array('name'=>'AAA'));
2857         } catch (Exception $e) {
2858             //TODO: ignore case insensitive uniqueness problems for now
2859             //$this->fail("Unique index is case sensitive - this may cause problems in some tables");
2860         }
2862         try {
2863             $DB->insert_record($tablename, array('name'=>'aäa'));
2864             $DB->insert_record($tablename, array('name'=>'aáa'));
2865             $this->assertTrue(true);
2866         } catch (Exception $e) {
2867             $family = $DB->get_dbfamily();
2868             if ($family === 'mysql' or $family === 'mssql') {
2869                 $this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages. This is usually caused by accent insensitive default collation.");
2870             } else {
2871                 // this should not happen, PostgreSQL and Oracle do not support accent insensitive uniqueness.
2872                 $this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages.");
2873             }
2874             throw($e);
2875         }
2876     }
2878     function test_sql_binary_equal() {
2879         $DB = $this->tdb;
2880         $dbman = $DB->get_manager();
2882         $table = $this->get_test_table();
2883         $tablename = $table->getName();
2885         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2886         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2887         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2888         $dbman->create_table($table);
2890         $DB->insert_record($tablename, array('name'=>'aaa'));
2891         $DB->insert_record($tablename, array('name'=>'aáa'));
2892         $DB->insert_record($tablename, array('name'=>'aäa'));
2893         $DB->insert_record($tablename, array('name'=>'bbb'));
2894         $DB->insert_record($tablename, array('name'=>'BBB'));
2896         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('aaa'));
2897         $this->assertEqual(count($records), 1, 'SQL operator "=" is expected to be accent sensitive');
2899         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('bbb'));
2900         $this->assertEqual(count($records), 1, 'SQL operator "=" is expected to be case sensitive');
2901     }
2903     function test_sql_like() {
2904         $DB = $this->tdb;
2905         $dbman = $DB->get_manager();
2907         $table = $this->get_test_table();
2908         $tablename = $table->getName();
2910         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2911         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2912         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2913         $dbman->create_table($table);
2915         $DB->insert_record($tablename, array('name'=>'SuperDuperRecord'));
2916         $DB->insert_record($tablename, array('name'=>'Nodupor'));
2917         $DB->insert_record($tablename, array('name'=>'ouch'));
2918         $DB->insert_record($tablename, array('name'=>'ouc_'));
2919         $DB->insert_record($tablename, array('name'=>'ouc%'));
2920         $DB->insert_record($tablename, array('name'=>'aui'));
2921         $DB->insert_record($tablename, array('name'=>'aüi'));
2922         $DB->insert_record($tablename, array('name'=>'aÜi'));
2924         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false);
2925         $records = $DB->get_records_sql($sql, array("%dup_r%"));
2926         $this->assertEqual(count($records), 2);
2928         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true);
2929         $records = $DB->get_records_sql($sql, array("%dup%"));
2930         $this->assertEqual(count($records), 1);
2932         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?'); // defaults
2933         $records = $DB->get_records_sql($sql, array("%dup%"));
2934         $this->assertEqual(count($records), 1);
2936         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true);
2937         $records = $DB->get_records_sql($sql, array("ouc\\_"));
2938         $this->assertEqual(count($records), 1);
2940         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true, false, '|');
2941         $records = $DB->get_records_sql($sql, array($DB->sql_like_escape("ouc%", '|')));
2942         $this->assertEqual(count($records), 1);
2944         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true);
2945         $records = $DB->get_records_sql($sql, array('aui'));
2946         $this->assertEqual(count($records), 1);
2948         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true, true); // NOT LIKE
2949         $records = $DB->get_records_sql($sql, array("%o%"));
2950         $this->assertEqual(count($records), 3);
2952         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false, true, true); // NOT ILIKE
2953         $records = $DB->get_records_sql($sql, array("%D%"));
2954         $this->assertEqual(count($records), 6);
2956         // TODO: we do not require accent insensitivness yet, just make sure it does not throw errors
2957         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, false);
2958         $records = $DB->get_records_sql($sql, array('aui'));
2959         //$this->assertEqual(count($records), 2, 'Accent insensitive LIKE searches may not be supported in all databases, this is not a problem.');
2960         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false, false);
2961         $records = $DB->get_records_sql($sql, array('aui'));
2962         //$this->assertEqual(count($records), 3, 'Accent insensitive LIKE searches may not be supported in all databases, this is not a problem.');
2963     }
2965     function test_sql_ilike() {
2966         // note: this is deprecated, just make sure it does not throw error
2967         $DB = $this->tdb;
2968         $dbman = $DB->get_manager();
2970         $table = $this->get_test_table();
2971         $tablename = $table->getName();
2973         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2974         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2975         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2976         $dbman->create_table($table);
2978         $DB->insert_record($tablename, array('name'=>'SuperDuperRecord'));
2979         $DB->insert_record($tablename, array('name'=>'NoDupor'));
2980         $DB->insert_record($tablename, array('name'=>'ouch'));
2982         // make sure it prints debug message
2983         $this->enable_debugging();
2984         $sql = "SELECT * FROM {{$tablename}} WHERE name ".$DB->sql_ilike()." ?";
2985         $params = array("%dup_r%");
2986         $this->assertFalse($this->get_debugging() === '');
2988         // following must not throw exception, we ignore result
2989         $DB->get_records_sql($sql, $params);
2990     }
2992     function test_sql_concat() {
2993         $DB = $this->tdb;
2994         $dbman = $DB->get_manager();
2996         /// Testing all sort of values
2997         $sql = "SELECT ".$DB->sql_concat("?", "?", "?")." AS fullname ". $DB->sql_null_from_clause();
2998         // string, some unicode chars
2999         $params = array('name', 'áéíóú', 'name3');
3000         $this->assertEqual('nameáéíóúname3', $DB->get_field_sql($sql, $params));
3001         // string, spaces and numbers
3002         $params = array('name', '  ', 12345);
3003         $this->assertEqual('name  12345', $DB->get_field_sql($sql, $params));
3004         // float, empty and strings
3005         $params = array(123.45, '', 'test');
3006         $this->assertEqual('123.45test', $DB->get_field_sql($sql, $params));
3007         // only integers
3008         $params = array(12, 34, 56);
3009         $this->assertEqual('123456', $DB->get_field_sql($sql, $params));
3010         // float, null and strings
3011         $params = array(123.45, null, 'test');
3012         $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
3014         /// Testing fieldnames + values and also integer fieldnames
3015         $table = $this->get_test_table();
3016         $tablename = $table->getName();
3018         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3019         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
3020         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3021         $dbman->create_table($table);
3023         $DB->insert_record($tablename, array('description'=>'áéíóú'));
3024         $DB->insert_record($tablename, array('description'=>'dxxx'));
3025         $DB->insert_record($tablename, array('description'=>'bcde'));
3027         // fieldnames and values mixed
3028         $sql = 'SELECT id, ' . $DB->sql_concat('description', "'harcoded'", '?', '?') . ' AS result FROM {' . $tablename . '}';
3029         $records = $DB->get_records_sql($sql, array(123.45, 'test'));
3030         $this->assertEqual(count($records), 3);
3031         $this->assertEqual($records[1]->result, 'áéíóúharcoded123.45test');
3032         // integer fieldnames and values
3033         $sql = 'SELECT id, ' . $DB->sql_concat('id', "'harcoded'", '?', '?') . ' AS result FROM {' . $tablename . '}';
3034         $records = $DB->get_records_sql($sql, array(123.45, 'test'));
3035         $this->assertEqual(count($records), 3);
3036         $this->assertEqual($records[1]->result, '1harcoded123.45test');
3037         // all integer fieldnames
3038         $sql = 'SELECT id, ' . $DB->sql_concat('id', 'id', 'id') . ' AS result FROM {' . $tablename . '}';
3039         $records = $DB->get_records_sql($sql, array());
3040         $this->assertEqual(count($records), 3);
3041         $this->assertEqual($records[1]->result, '111');
3043     }
3045     function test_concat_join() {
3046         $DB = $this->tdb;
3047         $sql = "SELECT ".$DB->sql_concat_join("' '", array("?", "?", "?"))." AS fullname ".$DB->sql_null_from_clause();
3048         $params = array("name", "name2", "name3");
3049         $result = $DB->get_field_sql($sql, $params);
3050         $this->assertEqual("name name2 name3", $result);
3051     }
3053     function test_sql_fullname() {
3054         $DB = $this->tdb;
3055         $sql = "SELECT ".$DB->sql_fullname(':first', ':last')." AS fullname ".$DB->sql_null_from_clause();
3056         $params = array('first'=>'Firstname', 'last'=>'Surname');
3057         $this->assertEqual("Firstname Surname", $DB->get_field_sql($sql, $params));
3058     }
3060     function sql_sql_order_by_text() {
3061         $DB = $this->tdb;
3062         $dbman = $DB->get_manager();
3064         $table = $this->get_test_table();
3065         $tablename = $table->getName();
3067         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3068         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
3069         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3070         $dbman->create_table($table);
3072         $DB->insert_record($tablename, array('description'=>'abcd'));
3073         $DB->insert_record($tablename, array('description'=>'dxxx'));
3074         $DB->insert_record($tablename, array('description'=>'bcde'));
3076         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_order_by_text('description');
3077         $records = $DB->get_records_sql($sql);
3078         $first = array_shift($records);
3079         $this->assertEqual(1, $first->id);
3080         $second = array_shift($records);
3081         $this->assertEqual(3, $second->id);
3082         $last = array_shift($records);
3083         $this->assertEqual(2, $last->id);
3084     }
3086     function test_sql_substring() {
3087         $DB = $this->tdb;
3088         $dbman = $DB->get_manager();
3090         $table = $this->get_test_table();
3091         $tablename = $table->getName();
3093         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3094         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3095         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3096         $dbman->create_table($table);
3098         $string = 'abcdefghij';
3100         $DB->insert_record($tablename, array('name'=>$string));
3102         $sql = "SELECT id, ".$DB->sql_substr("name", 5)." AS name FROM {{$tablename}}";
3103         $record = $DB->get_record_sql($sql);
3104         $this->assertEqual(substr($string, 5-1), $record->name);
3106         $sql = "SELECT id, ".$DB->sql_substr("name", 5, 2)." AS name FROM {{$tablename}}";
3107         $record = $DB->get_record_sql($sql);
3108         $this->assertEqual(substr($string, 5-1, 2), $record->name);
3110         try {
3111             // silence php warning ;-)
3112             @$DB->sql_substr("name");
3113             $this->fail("Expecting an exception, none occurred");
3114         } catch (Exception $e) {
3115             $this->assertTrue($e instanceof coding_exception);
3116         }
3117     }
3119     function test_sql_length() {
3120         $DB = $this->tdb;
3121         $this->assertEqual($DB->get_field_sql(
3122                 "SELECT ".$DB->sql_length("'aeiou'").$DB->sql_null_from_clause()), 5);
3123         $this->assertEqual($DB->get_field_sql(
3124                 "SELECT ".$DB->sql_length("'áéíóú'").$DB->sql_null_from_clause()), 5);
3125     }
3127     function test_sql_position() {
3128         $DB = $this->tdb;
3129         $this->assertEqual($DB->get_field_sql(
3130                 "SELECT ".$DB->sql_position("'ood'", "'Moodle'").$DB->sql_null_from_clause()), 2);
3131         $this->assertEqual($DB->get_field_sql(
3132                 "SELECT ".$DB->sql_position("'Oracle'", "'Moodle'").$DB->sql_null_from_clause()), 0);
3133     }
3135     function test_sql_empty() {
3136         $DB = $this->tdb;
3137         $dbman = $DB->get_manager();
3139         $table = $this->get_test_table();
3140         $tablename = $table->getName();
3142         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3143         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3144         $table->add_field('namenotnull', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'default value');
3145         $table->add_field('namenotnullnodeflt', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
3146         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3147         $dbman->create_table($table);
3149         $DB->insert_record($tablename, array('name'=>'', 'namenotnull'=>''));
3150         $DB->insert_record($tablename, array('name'=>null));
3151         $DB->insert_record($tablename, array('name'=>'lalala'));
3152         $DB->insert_record($tablename, array('name'=>0));
3154         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = '".$DB->sql_empty()."'");
3155         $this->assertEqual(count($records), 1);
3156         $record = reset($records);
3157         $this->assertEqual($record->name, '');
3159         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE namenotnull = '".$DB->sql_empty()."'");
3160         $this->assertEqual(count($records), 1);
3161         $record = reset($records);
3162         $this->assertEqual($record->namenotnull, '');
3164         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE namenotnullnodeflt = '".$DB->sql_empty()."'");
3165         $this->assertEqual(count($records), 4);
3166         $record = reset($records);
3167         $this->assertEqual($record->namenotnullnodeflt, '');
3168     }
3170     function test_sql_isempty() {
3171         $DB = $this->tdb;
3172         $dbman = $DB->get_manager();
3174         $table = $this->get_test_table();
3175         $tablename = $table->getName();
3177         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3178         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
3179         $table->add_field('namenull', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3180         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null);
3181         $table->add_field('descriptionnull', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
3182         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3183         $dbman->create_table($table);
3185         $DB->insert_record($tablename, array('name'=>'',   'namenull'=>'',   'description'=>'',   'descriptionnull'=>''));
3186         $DB->insert_record($tablename, array('name'=>'??', 'namenull'=>null, 'description'=>'??', 'descriptionnull'=>null));
3187         $DB->insert_record($tablename, array('name'=>'la', 'namenull'=>'la', 'description'=>'la', 'descriptionnull'=>'lalala'));
3188         $DB->insert_record($tablename, array('name'=>0,    'namenull'=>0,    'description'=>0,    'descriptionnull'=>0));
3190         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isempty($tablename, 'name', false, false));
3191         $this->assertEqual(count($records), 1);
3192         $record = reset($records);
3193         $this->assertEqual($record->name, '');
3195         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isempty($tablename, 'namenull', true, false));
3196         $this->assertEqual(count($records), 1);
3197         $record = reset($records);
3198         $this->assertEqual($record->namenull, '');
3200         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isempty($tablename, 'description', false, true));
3201         $this->assertEqual(count($records), 1);
3202         $record = reset($records);
3203         $this->assertEqual($record->description, '');
3205         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isempty($tablename, 'descriptionnull', true, true));
3206         $this->assertEqual(count($records), 1);
3207         $record = reset($records);
3208         $this->assertEqual($record->descriptionnull, '');
3209     }
3211     function test_sql_isnotempty() {
3212         $DB = $this->tdb;
3213         $dbman = $DB->get_manager();
3215         $table = $this->get_test_table();
3216         $tablename = $table->getName();
3218         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3219         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
3220         $table->add_field('namenull', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3221         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null);
3222         $table->add_field('descriptionnull', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
3223         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3224         $dbman->create_table($table);
3226         $DB->insert_record($tablename, array('name'=>'',   'namenull'=>'',   'description'=>'',   'descriptionnull'=>''));
3227         $DB->insert_record($tablename, array('name'=>'??', 'namenull'=>null, 'description'=>'??', 'descriptionnull'=>null));
3228         $DB->insert_record($tablename, array('name'=>'la', 'namenull'=>'la', 'description'=>'la', 'descriptionnull'=>'lalala'));
3229         $DB->insert_record($tablename, array('name'=>0,    'namenull'=>0,    'description'=>0,    'descriptionnull'=>0));
3231         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isnotempty($tablename, 'name', false, false));
3232         $this->assertEqual(count($records), 3);
3233         $record = reset($records);
3234         $this->assertEqual($record->name, '??');
3236         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isnotempty($tablename, 'namenull', true, false));
3237         $this->assertEqual(count($records), 2); // nulls aren't comparable (so they aren't "not empty"). SQL expected behaviour
3238         $record = reset($records);
3239         $this->assertEqual($record->namenull, 'la'); // so 'la' is the first non-empty 'namenull' record
3241         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isnotempty($tablename, 'description', false, true));
3242         $this->assertEqual(count($records), 3);
3243         $record = reset($records);
3244         $this->assertEqual($record->description, '??');
3246         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE ".$DB->sql_isnotempty($tablename, 'descriptionnull', true, true));
3247         $this->assertEqual(count($records), 2); // nulls aren't comparable (so they aren't "not empty"). SQL expected behaviour
3248         $record = reset($records);
3249         $this->assertEqual($record->descriptionnull, 'lalala'); // so 'lalala' is the first non-empty 'descriptionnull' record
3250     }
3252     function test_sql_regex() {
3253         $DB = $this->tdb;
3254         $dbman = $DB->get_manager();
3256         $table = $this->get_test_table();
3257         $tablename = $table->getName();
3259         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3260         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3261         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3262         $dbman->create_table($table);
3264         $DB->insert_record($tablename, array('name'=>'lalala'));
3265         $DB->insert_record($tablename, array('name'=>'holaaa'));
3266         $DB->insert_record($tablename, array('name'=>'aouch'));
3268         $sql = "SELECT * FROM {{$tablename}} WHERE name ".$DB->sql_regex()." ?";
3269         $params = array('a$');
3270         if ($DB->sql_regex_supported()) {
3271             $records = $DB->get_records_sql($sql, $params);
3272             $this->assertEqual(count($records), 2);
3273         } else {
3274             $this->assertTrue(true, 'Regexp operations not supported. Test skipped');
3275         }
3277         $sql = "SELECT * FROM {{$tablename}} WHERE name ".$DB->sql_regex(false)." ?";
3278         $params = array('.a');
3279         if ($DB->sql_regex_supported()) {
3280             $records = $DB->get_records_sql($sql, $params);
3281             $this->assertEqual(count($records), 1);
3282         } else {
3283             $this->assertTrue(true,&