3 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
21 * @copyright 2008 Petr Skoda (http://skodak.org)
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') || die();
27 class dml_test extends UnitTestCase {
28 private $tables = array();
31 public static $includecoverage = array('lib/dml');
32 public static $excludecoverage = array('lib/dml/simpletest');
35 global $CFG, $DB, $UNITTEST;
37 if (isset($UNITTEST->func_test_db)) {
38 $this->tdb = $UNITTEST->func_test_db;
46 $dbman = $this->tdb->get_manager();
48 foreach ($this->tables as $table) {
49 if ($dbman->table_exists($table)) {
50 $dbman->drop_table($table);
53 $this->tables = array();
57 * Get a xmldb_table object for testing, deleting any existing table
58 * of the same name, for example if one was left over from a previous test
61 * @param database_manager $dbman the database_manager to use.
62 * @param string $tablename the name of the table to create.
63 * @return xmldb_table the table object.
65 private function get_test_table($tablename="") {
67 $dbman = $this->tdb->get_manager();
69 if ($tablename == '') {
70 $tablename = "unit_table";
73 $table = new xmldb_table($tablename);
74 if ($dbman->table_exists($table)) {
75 $dbman->drop_table($table);
77 return new xmldb_table($tablename);
80 function test_fix_sql_params() {
83 $table = $this->get_test_table();
84 $tablename = $table->getName();
86 // Correct table placeholder substitution
87 $sql = "SELECT * FROM {".$tablename."}";
88 $sqlarray = $DB->fix_sql_params($sql);
89 $this->assertEqual("SELECT * FROM {$DB->get_prefix()}".$tablename, $sqlarray[0]);
91 // Conversions of all param types
93 $sql[SQL_PARAMS_NAMED] = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = :param1, course = :param2";
94 $sql[SQL_PARAMS_QM] = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = ?, course = ?";
95 $sql[SQL_PARAMS_DOLLAR] = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = \$1, course = \$2";
98 $params[SQL_PARAMS_NAMED] = array('param1'=>'first record', 'param2'=>1);
99 $params[SQL_PARAMS_QM] = array('first record', 1);
100 $params[SQL_PARAMS_DOLLAR] = array('first record', 1);
102 list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_NAMED], $params[SQL_PARAMS_NAMED]);
103 $this->assertEqual($rsql, $sql[$rtype]);
104 $this->assertEqual($rparams, $params[$rtype]);
106 list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_QM], $params[SQL_PARAMS_QM]);
107 $this->assertEqual($rsql, $sql[$rtype]);
108 $this->assertEqual($rparams, $params[$rtype]);
110 list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_DOLLAR], $params[SQL_PARAMS_DOLLAR]);
111 $this->assertEqual($rsql, $sql[$rtype]);
112 $this->assertEqual($rparams, $params[$rtype]);
115 // Malformed table placeholder
116 $sql = "SELECT * FROM [testtable]";
117 $sqlarray = $DB->fix_sql_params($sql);
118 $this->assertEqual($sql, $sqlarray[0]);
121 // Mixed param types (colon and dollar)
122 $sql = "SELECT * FROM {".$tablename."} WHERE name = :param1, course = \$1";
123 $params = array('param1' => 'record1', 'param2' => 3);
125 $sqlarray = $DB->fix_sql_params($sql, $params);
126 $this->fail("Expecting an exception, none occurred");
127 } catch (Exception $e) {
128 $this->assertTrue($e instanceof moodle_exception);
131 // Mixed param types (question and dollar)
132 $sql = "SELECT * FROM {".$tablename."} WHERE name = ?, course = \$1";
133 $params = array('param1' => 'record2', 'param2' => 5);
135 $sqlarray = $DB->fix_sql_params($sql, $params);
136 $this->fail("Expecting an exception, none occurred");
137 } catch (Exception $e) {
138 $this->assertTrue($e instanceof moodle_exception);
141 // Too many params in sql
142 $sql = "SELECT * FROM {".$tablename."} WHERE name = ?, course = ?, id = ?";
143 $params = array('record2', 3);
145 $sqlarray = $DB->fix_sql_params($sql, $params);
146 $this->fail("Expecting an exception, none occurred");
147 } catch (Exception $e) {
148 $this->assertTrue($e instanceof moodle_exception);
151 // Too many params in array: no error
157 $sqlarray = $DB->fix_sql_params($sql, $params);
159 } catch (Exception $e) {
160 $this->fail("Unexpected ".get_class($e)." exception");
162 $this->assertTrue($sqlarray[0]);
164 // Named params missing from array
165 $sql = "SELECT * FROM {".$tablename."} WHERE name = :name, course = :course";
166 $params = array('wrongname' => 'record1', 'course' => 1);
168 $sqlarray = $DB->fix_sql_params($sql, $params);
169 $this->fail("Expecting an exception, none occurred");
170 } catch (Exception $e) {
171 $this->assertTrue($e instanceof moodle_exception);
174 // Duplicate named param in query
175 $sql = "SELECT * FROM {".$tablename."} WHERE name = :name, course = :name";
176 $params = array('name' => 'record2', 'course' => 3);
178 $sqlarray = $DB->fix_sql_params($sql, $params);
179 $this->fail("Expecting an exception, none occurred");
180 } catch (Exception $e) {
181 $this->assertTrue($e instanceof moodle_exception);
183 // Booleans in NAMED params are casting to 1/0 int
184 $sql = "SELECT * FROM {".$tablename."} WHERE course = ? OR course = ?";
185 $params = array(true, false);
186 list($sql, $params) = $DB->fix_sql_params($sql, $params);
187 $this->assertTrue(reset($params) === 1);
188 $this->assertTrue(next($params) === 0);
190 // Booleans in QM params are casting to 1/0 int
191 $sql = "SELECT * FROM {".$tablename."} WHERE course = :course1 OR course = :course2";
192 $params = array('course1' => true, 'course2' => false);
193 list($sql, $params) = $DB->fix_sql_params($sql, $params);
194 $this->assertTrue(reset($params) === 1);
195 $this->assertTrue(next($params) === 0);
197 // Booleans in DOLLAR params are casting to 1/0 int
198 $sql = "SELECT * FROM {".$tablename."} WHERE course = \$1 OR course = \$2";
199 $params = array(true, false);
200 list($sql, $params) = $DB->fix_sql_params($sql, $params);
201 $this->assertTrue(reset($params) === 1);
202 $this->assertTrue(next($params) === 0);
205 public function testGetTables() {
207 $dbman = $this->tdb->get_manager();
209 // Need to test with multiple DBs
210 $table = $this->get_test_table();
211 $tablename = $table->getName();
213 $original_count = count($DB->get_tables());
215 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
216 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
217 $dbman->create_table($table);
218 $this->tables[$tablename] = $table;
220 $this->assertTrue(count($DB->get_tables()) == $original_count + 1);
223 public function testDefaults() {
225 $dbman = $this->tdb->get_manager();
227 $table = $this->get_test_table();
228 $tablename = $table->getName();
230 $table->add_field('enumfield', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'test2');
231 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
232 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
233 $dbman->create_table($table);
234 $this->tables[$tablename] = $table;
236 $columns = $DB->get_columns($tablename);
238 $enumfield = $columns['enumfield'];
239 $this->assertEqual('test2', $enumfield->default_value);
240 $this->assertEqual('C', $enumfield->meta_type);
244 public function testGetIndexes() {
246 $dbman = $this->tdb->get_manager();
248 $table = $this->get_test_table();
249 $tablename = $table->getName();
251 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
252 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
253 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
254 $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
255 $table->add_index('course-id', XMLDB_INDEX_UNIQUE, array('course', 'id'));
256 $dbman->create_table($table);
257 $this->tables[$tablename] = $table;
259 $this->assertTrue($indices = $DB->get_indexes($tablename));
260 $this->assertEqual(count($indices), 2);
261 // we do not care about index names for now
262 $first = array_shift($indices);
263 $second = array_shift($indices);
264 if (count($first['columns']) == 2) {
271 $this->assertFalse($single['unique']);
272 $this->assertTrue($composed['unique']);
273 $this->assertEqual(1, count($single['columns']));
274 $this->assertEqual(2, count($composed['columns']));
275 $this->assertEqual('course', $single['columns'][0]);
276 $this->assertEqual('course', $composed['columns'][0]);
277 $this->assertEqual('id', $composed['columns'][1]);
280 public function testGetColumns() {
282 $dbman = $this->tdb->get_manager();
284 $table = $this->get_test_table();
285 $tablename = $table->getName();
287 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
288 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
289 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
290 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
291 $dbman->create_table($table);
292 $this->tables[$tablename] = $table;
294 $this->assertTrue($columns = $DB->get_columns($tablename));
295 $fields = $this->tables[$tablename]->getFields();
296 $this->assertEqual(count($columns), count($fields));
298 for ($i = 0; $i < count($columns); $i++) {
300 $next_column = reset($columns);
301 $next_field = reset($fields);
303 $next_column = next($columns);
304 $next_field = next($fields);
307 $this->assertEqual($next_column->name, $next_field->name);
311 public function testExecute() {
313 $dbman = $this->tdb->get_manager();
315 $table = $this->get_test_table();
316 $tablename = $table->getName();
318 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
319 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
320 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
321 $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
322 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
323 $dbman->create_table($table);
324 $this->tables[$tablename] = $table;
326 $sql = "SELECT * FROM {".$tablename."}";
328 $this->assertTrue($DB->execute($sql));
330 $params = array('course' => 1, 'name' => 'test');
332 $sql = "INSERT INTO {".$tablename."} (".implode(',', array_keys($params)).")
333 VALUES (".implode(',', array_fill(0, count($params), '?')).")";
336 $this->assertTrue($DB->execute($sql, $params));
338 $record = $DB->get_record($tablename, array('id' => 1));
340 foreach ($params as $field => $value) {
341 $this->assertEqual($value, $record->$field, "Field $field in DB ({$record->$field}) is not equal to field $field in sql ($value)");
345 public function test_get_in_or_equal() {
348 // SQL_PARAMS_QM - IN or =
350 // Correct usage of multiple values
351 $in_values = array('value1', 'value2', 'value3', 'value4');
352 list($usql, $params) = $DB->get_in_or_equal($in_values);
353 $this->assertEqual("IN (?,?,?,?)", $usql);
354 $this->assertEqual(4, count($params));
355 foreach ($params as $key => $value) {
356 $this->assertEqual($in_values[$key], $value);
359 // Correct usage of single value (in an array)
360 $in_values = array('value1');
361 list($usql, $params) = $DB->get_in_or_equal($in_values);
362 $this->assertEqual("= ?", $usql);
363 $this->assertEqual(1, count($params));
364 $this->assertEqual($in_values[0], $params[0]);
366 // Correct usage of single value
367 $in_value = 'value1';
368 list($usql, $params) = $DB->get_in_or_equal($in_values);
369 $this->assertEqual("= ?", $usql);
370 $this->assertEqual(1, count($params));
371 $this->assertEqual($in_value, $params[0]);
373 // SQL_PARAMS_QM - NOT IN or <>
375 // Correct usage of multiple values
376 $in_values = array('value1', 'value2', 'value3', 'value4');
377 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
378 $this->assertEqual("NOT IN (?,?,?,?)", $usql);
379 $this->assertEqual(4, count($params));
380 foreach ($params as $key => $value) {
381 $this->assertEqual($in_values[$key], $value);
384 // Correct usage of single value (in array()
385 $in_values = array('value1');
386 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
387 $this->assertEqual("<> ?", $usql);
388 $this->assertEqual(1, count($params));
389 $this->assertEqual($in_values[0], $params[0]);
391 // Correct usage of single value
392 $in_value = 'value1';
393 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
394 $this->assertEqual("<> ?", $usql);
395 $this->assertEqual(1, count($params));
396 $this->assertEqual($in_value, $params[0]);
398 // SQL_PARAMS_NAMED - IN or =
400 // Correct usage of multiple values
401 $in_values = array('value1', 'value2', 'value3', 'value4');
402 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', true);
403 $this->assertEqual("IN (:param01,:param02,:param03,:param04)", $usql);
404 $this->assertEqual(4, count($params));
406 foreach ($params as $key => $value) {
407 $this->assertEqual(current($in_values), $value);
411 // Correct usage of single values (in array)
412 $in_values = array('value1');
413 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', true);
414 $this->assertEqual("= :param01", $usql);
415 $this->assertEqual(1, count($params));
416 $this->assertEqual($in_values[0], $params['param01']);
418 // Correct usage of single value
419 $in_value = 'value1';
420 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', true);
421 $this->assertEqual("= :param01", $usql);
422 $this->assertEqual(1, count($params));
423 $this->assertEqual($in_value, $params['param01']);
425 // SQL_PARAMS_NAMED - NOT IN or <>
427 // Correct usage of multiple values
428 $in_values = array('value1', 'value2', 'value3', 'value4');
429 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
430 $this->assertEqual("NOT IN (:param01,:param02,:param03,:param04)", $usql);
431 $this->assertEqual(4, count($params));
433 foreach ($params as $key => $value) {
434 $this->assertEqual(current($in_values), $value);
438 // Correct usage of single values (in array)
439 $in_values = array('value1');
440 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
441 $this->assertEqual("<> :param01", $usql);
442 $this->assertEqual(1, count($params));
443 $this->assertEqual($in_values[0], $params['param01']);
445 // Correct usage of single value
446 $in_value = 'value1';
447 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param01', false);
448 $this->assertEqual("<> :param01", $usql);
449 $this->assertEqual(1, count($params));
450 $this->assertEqual($in_value, $params['param01']);
454 public function test_fix_table_names() {
455 $DB = new moodle_database_for_testing();
456 $prefix = $DB->get_prefix();
458 // Simple placeholder
459 $placeholder = "{user}";
460 $this->assertEqual($prefix."user", $DB->public_fix_table_names($placeholder));
463 $sql = "SELECT * FROM {user}, {funny_table_name}, {mdl_stupid_table} WHERE {user}.id = {funny_table_name}.userid";
464 $expected = "SELECT * FROM {$prefix}user, {$prefix}funny_table_name, {$prefix}mdl_stupid_table WHERE {$prefix}user.id = {$prefix}funny_table_name.userid";
465 $this->assertEqual($expected, $DB->public_fix_table_names($sql));
470 public function test_get_recordset() {
472 $dbman = $DB->get_manager();
474 $table = $this->get_test_table();
475 $tablename = $table->getName();
477 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
478 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
479 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
480 $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
481 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
482 $dbman->create_table($table);
483 $this->tables[$tablename] = $table;
485 $data = array(array('id' => 1, 'course' => 3, 'name' => 'record1'),
486 array('id' => 2, 'course' => 3, 'name' => 'record2'),
487 array('id' => 3, 'course' => 5, 'name' => 'record3'));
489 foreach ($data as $record) {
490 $DB->insert_record($tablename, $record);
493 $rs = $DB->get_recordset($tablename);
494 $this->assertTrue($rs);
497 foreach($rs as $record) {
498 $data_record = current($data);
499 foreach ($record as $k => $v) {
500 $this->assertEqual($data_record[$k], $v);
506 // note: delegate limits testing to test_get_recordset_sql()
509 public function test_get_recordset_iterator_keys() {
511 $dbman = $DB->get_manager();
513 $table = $this->get_test_table();
514 $tablename = $table->getName();
516 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
517 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
518 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
519 $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
520 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
521 $dbman->create_table($table);
522 $this->tables[$tablename] = $table;
524 $data = array(array('id'=> 1, 'course' => 3, 'name' => 'record1'),
525 array('id'=> 2, 'course' => 3, 'name' => 'record2'),
526 array('id'=> 3, 'course' => 5, 'name' => 'record3'));
527 foreach ($data as $record) {
528 $DB->insert_record($tablename, $record);
531 /// Test repeated numeric keys are returned ok
532 $rs = $DB->get_recordset($tablename, NULL, NULL, 'course, name, id');
536 foreach($rs as $key => $record) {
537 $data_record = current($data);
538 $this->assertEqual($data_record['course'], $key);
544 /// Test record returned are ok
545 $this->assertEqual($count, 3);
547 /// Test string keys are returned ok
548 $rs = $DB->get_recordset($tablename, NULL, NULL, 'name, course, id');
552 foreach($rs as $key => $record) {
553 $data_record = current($data);
554 $this->assertEqual($data_record['name'], $key);
560 /// Test record returned are ok
561 $this->assertEqual($count, 3);
563 /// Test numeric not starting in 1 keys are returned ok
564 $rs = $DB->get_recordset($tablename, NULL, 'id DESC', 'id, course, name');
566 $data = array_reverse($data);
569 foreach($rs as $key => $record) {
570 $data_record = current($data);
571 $this->assertEqual($data_record['id'], $key);
577 /// Test record returned are ok
578 $this->assertEqual($count, 3);
581 public function test_get_recordset_list() {
583 $dbman = $DB->get_manager();
585 $table = $this->get_test_table();
586 $tablename = $table->getName();
588 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
589 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
590 $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
591 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
592 $dbman->create_table($table);
593 $this->tables[$tablename] = $table;
595 $DB->insert_record($tablename, array('course' => 3));
596 $DB->insert_record($tablename, array('course' => 3));
597 $DB->insert_record($tablename, array('course' => 5));
598 $DB->insert_record($tablename, array('course' => 2));
600 $rs = $DB->get_recordset_list($tablename, 'course', array(3, 2));
602 $this->assertTrue($rs);
605 foreach ($rs as $record) {
608 $this->assertEqual(3, $counter);
611 $rs = $DB->get_recordset_list($tablename, 'course',array()); /// Must return 0 rows without conditions. MDL-17645
614 foreach ($rs as $record) {
618 $this->assertEqual(0, $counter);
620 // note: delegate limits testing to test_get_recordset_sql()
623 public function test_get_recordset_select() {
625 $dbman = $DB->get_manager();
627 $table = $this->get_test_table();
628 $tablename = $table->getName();
630 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
631 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
632 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
633 $dbman->create_table($table);
634 $this->tables[$tablename] = $table;
636 $DB->insert_record($tablename, array('course' => 3));
637 $DB->insert_record($tablename, array('course' => 3));
638 $DB->insert_record($tablename, array('course' => 5));
639 $DB->insert_record($tablename, array('course' => 2));
641 $rs = $DB->get_recordset_select($tablename, '');
643 foreach ($rs as $record) {
647 $this->assertEqual(4, $counter);
649 $this->assertTrue($rs = $DB->get_recordset_select($tablename, 'course = 3'));
651 foreach ($rs as $record) {
655 $this->assertEqual(2, $counter);
657 // note: delegate limits testing to test_get_recordset_sql()
660 public function test_get_recordset_sql() {
662 $dbman = $DB->get_manager();
664 $table = $this->get_test_table();
665 $tablename = $table->getName();
667 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
668 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
669 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
670 $dbman->create_table($table);
671 $this->tables[$tablename] = $table;
673 $inskey1 = $DB->insert_record($tablename, array('course' => 3));
674 $inskey2 = $DB->insert_record($tablename, array('course' => 5));
675 $inskey3 = $DB->insert_record($tablename, array('course' => 4));
676 $inskey4 = $DB->insert_record($tablename, array('course' => 3));
677 $inskey5 = $DB->insert_record($tablename, array('course' => 2));
678 $inskey6 = $DB->insert_record($tablename, array('course' => 1));
679 $inskey7 = $DB->insert_record($tablename, array('course' => 0));
681 $this->assertTrue($rs = $DB->get_recordset_sql("SELECT * FROM {".$tablename."} WHERE course = ?", array(3)));
683 foreach ($rs as $record) {
687 $this->assertEqual(2, $counter);
689 // limits - only need to test this case, the rest have been tested by test_get_records_sql()
690 // only limitfrom = skips that number of records
691 $rs = $DB->get_recordset_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 2, 0);
693 foreach($rs as $key => $record) {
694 $records[$key] = $record;
697 $this->assertEqual(5, count($records));
698 $this->assertEqual($inskey3, reset($records)->id);
699 $this->assertEqual($inskey7, end($records)->id);
701 // note: fetching nulls, empties, LOBs already tested by test_insert_record() no needed here
704 public function test_get_records() {
706 $dbman = $DB->get_manager();
708 $table = $this->get_test_table();
709 $tablename = $table->getName();
711 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
712 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
713 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
714 $dbman->create_table($table);
715 $this->tables[$tablename] = $table;
717 $DB->insert_record($tablename, array('course' => 3));
718 $DB->insert_record($tablename, array('course' => 3));
719 $DB->insert_record($tablename, array('course' => 5));
720 $DB->insert_record($tablename, array('course' => 2));
723 $records = $DB->get_records($tablename);
724 $this->assertEqual(4, count($records));
725 $this->assertEqual(3, $records[1]->course);
726 $this->assertEqual(3, $records[2]->course);
727 $this->assertEqual(5, $records[3]->course);
728 $this->assertEqual(2, $records[4]->course);
730 // Records matching certain conditions
731 $records = $DB->get_records($tablename, array('course' => 3));
732 $this->assertEqual(2, count($records));
733 $this->assertEqual(3, $records[1]->course);
734 $this->assertEqual(3, $records[2]->course);
736 // All records sorted by course
737 $records = $DB->get_records($tablename, null, 'course');
738 $this->assertEqual(4, count($records));
739 $current_record = reset($records);
740 $this->assertEqual(4, $current_record->id);
741 $current_record = next($records);
742 $this->assertEqual(1, $current_record->id);
743 $current_record = next($records);
744 $this->assertEqual(2, $current_record->id);
745 $current_record = next($records);
746 $this->assertEqual(3, $current_record->id);
748 // All records, but get only one field
749 $records = $DB->get_records($tablename, null, '', 'id');
750 $this->assertTrue(empty($records[1]->course));
751 $this->assertFalse(empty($records[1]->id));
752 $this->assertEqual(4, count($records));
754 // Booleans into params
755 $records = $DB->get_records($tablename, array('course' => true));
756 $this->assertEqual(0, count($records));
757 $records = $DB->get_records($tablename, array('course' => false));
758 $this->assertEqual(0, count($records));
760 // note: delegate limits testing to test_get_records_sql()
763 public function test_get_records_list() {
765 $dbman = $DB->get_manager();
767 $table = $this->get_test_table();
768 $tablename = $table->getName();
770 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
771 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
772 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
773 $dbman->create_table($table);
774 $this->tables[$tablename] = $table;
776 $DB->insert_record($tablename, array('course' => 3));
777 $DB->insert_record($tablename, array('course' => 3));
778 $DB->insert_record($tablename, array('course' => 5));
779 $DB->insert_record($tablename, array('course' => 2));
781 $this->assertTrue($records = $DB->get_records_list($tablename, 'course', array(3, 2)));
782 $this->assertEqual(3, count($records));
783 $this->assertEqual(1, reset($records)->id);
784 $this->assertEqual(2, next($records)->id);
785 $this->assertEqual(4, next($records)->id);
787 $this->assertIdentical(array(), $records = $DB->get_records_list($tablename, 'course', array())); /// Must return 0 rows without conditions. MDL-17645
788 $this->assertEqual(0, count($records));
790 // note: delegate limits testing to test_get_records_sql()
793 public function test_get_record_select() {
795 $dbman = $DB->get_manager();
797 $table = $this->get_test_table();
798 $tablename = $table->getName();
800 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
801 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
802 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
803 $dbman->create_table($table);
804 $this->tables[$tablename] = $table;
806 $DB->insert_record($tablename, array('course' => 3));
807 $DB->insert_record($tablename, array('course' => 2));
809 $this->assertTrue($record = $DB->get_record_select($tablename, "id = ?", array(2)));
811 $this->assertEqual(2, $record->course);
813 // note: delegates limit testing to test_get_records_sql()
816 public function test_get_records_sql() {
819 $dbman = $DB->get_manager();
821 $table = $this->get_test_table();
822 $tablename = $table->getName();
824 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
825 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
826 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
827 $dbman->create_table($table);
828 $this->tables[$tablename] = $table;
830 $inskey1 = $DB->insert_record($tablename, array('course' => 3));
831 $inskey2 = $DB->insert_record($tablename, array('course' => 5));
832 $inskey3 = $DB->insert_record($tablename, array('course' => 4));
833 $inskey4 = $DB->insert_record($tablename, array('course' => 3));
834 $inskey5 = $DB->insert_record($tablename, array('course' => 2));
835 $inskey6 = $DB->insert_record($tablename, array('course' => 1));
836 $inskey7 = $DB->insert_record($tablename, array('course' => 0));
838 $this->assertTrue($records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE course = ?", array(3)));
839 $this->assertEqual(2, count($records));
840 $this->assertEqual($inskey1, reset($records)->id);
841 $this->assertEqual($inskey4, next($records)->id);
843 // Awful test, requires debug enabled and sent to browser. Let's do that and restore after test
844 $olddebug = $CFG->debug; // Save current debug settings
845 $olddisplay = $CFG->debugdisplay;
846 $CFG->debug = DEBUG_DEVELOPER;
847 $CFG->debugdisplay = true;
848 ob_start(); // hide debug warning
849 $records = $DB->get_records_sql("SELECT course AS id, course AS course FROM {".$tablename."}", null);
851 $debuginfo = ob_get_contents();
852 $CFG->debug = $olddebug; // Restore original debug settings
853 $CFG->debugdisplay = $olddisplay;
855 $this->assertEqual(6, count($records));
856 $this->assertFalse($debuginfo === '');
858 // negative limits = no limits
859 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, -1, -1);
860 $this->assertEqual(7, count($records));
862 // zero limits = no limits
863 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 0, 0);
864 $this->assertEqual(7, count($records));
866 // only limitfrom = skips that number of records
867 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 2, 0);
868 $this->assertEqual(5, count($records));
869 $this->assertEqual($inskey3, reset($records)->id);
870 $this->assertEqual($inskey7, end($records)->id);
872 // only limitnum = fetches that number of records
873 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 0, 3);
874 $this->assertEqual(3, count($records));
875 $this->assertEqual($inskey1, reset($records)->id);
876 $this->assertEqual($inskey3, end($records)->id);
878 // both limitfrom and limitnum = skips limitfrom records and fetches limitnum ones
879 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} ORDER BY id", null, 3, 2);
880 $this->assertEqual(2, count($records));
881 $this->assertEqual($inskey4, reset($records)->id);
882 $this->assertEqual($inskey5, end($records)->id);
884 // note: fetching nulls, empties, LOBs already tested by test_update_record() no needed here
887 public function test_get_records_menu() {
889 $dbman = $DB->get_manager();
891 $table = $this->get_test_table();
892 $tablename = $table->getName();
894 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
895 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
896 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
897 $dbman->create_table($table);
898 $this->tables[$tablename] = $table;
900 $DB->insert_record($tablename, array('course' => 3));
901 $DB->insert_record($tablename, array('course' => 3));
902 $DB->insert_record($tablename, array('course' => 5));
903 $DB->insert_record($tablename, array('course' => 2));
905 $this->assertTrue($records = $DB->get_records_menu($tablename, array('course' => 3)));
906 $this->assertEqual(2, count($records));
907 $this->assertFalse(empty($records[1]));
908 $this->assertFalse(empty($records[2]));
909 $this->assertEqual(3, $records[1]);
910 $this->assertEqual(3, $records[2]);
912 // note: delegate limits testing to test_get_records_sql()
915 public function test_get_records_select_menu() {
917 $dbman = $DB->get_manager();
919 $table = $this->get_test_table();
920 $tablename = $table->getName();
922 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
923 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
924 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
925 $dbman->create_table($table);
926 $this->tables[$tablename] = $table;
928 $DB->insert_record($tablename, array('course' => 3));
929 $DB->insert_record($tablename, array('course' => 2));
930 $DB->insert_record($tablename, array('course' => 3));
931 $DB->insert_record($tablename, array('course' => 5));
933 $this->assertTrue($records = $DB->get_records_select_menu($tablename, "course > ?", array(2)));
935 $this->assertEqual(3, count($records));
936 $this->assertFalse(empty($records[1]));
937 $this->assertTrue(empty($records[2]));
938 $this->assertFalse(empty($records[3]));
939 $this->assertFalse(empty($records[4]));
940 $this->assertEqual(3, $records[1]);
941 $this->assertEqual(3, $records[3]);
942 $this->assertEqual(5, $records[4]);
944 // note: delegate limits testing to test_get_records_sql()
947 public function test_get_records_sql_menu() {
949 $dbman = $DB->get_manager();
951 $table = $this->get_test_table();
952 $tablename = $table->getName();
954 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
955 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
956 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
957 $dbman->create_table($table);
958 $this->tables[$tablename] = $table;
960 $DB->insert_record($tablename, array('course' => 3));
961 $DB->insert_record($tablename, array('course' => 2));
962 $DB->insert_record($tablename, array('course' => 3));
963 $DB->insert_record($tablename, array('course' => 5));
965 $this->assertTrue($records = $DB->get_records_sql_menu("SELECT * FROM {".$tablename."} WHERE course > ?", array(2)));
967 $this->assertEqual(3, count($records));
968 $this->assertFalse(empty($records[1]));
969 $this->assertTrue(empty($records[2]));
970 $this->assertFalse(empty($records[3]));
971 $this->assertFalse(empty($records[4]));
972 $this->assertEqual(3, $records[1]);
973 $this->assertEqual(3, $records[3]);
974 $this->assertEqual(5, $records[4]);
976 // note: delegate limits testing to test_get_records_sql()
979 public function test_get_record() {
981 $dbman = $DB->get_manager();
983 $table = $this->get_test_table();
984 $tablename = $table->getName();
986 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
987 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
988 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
989 $dbman->create_table($table);
990 $this->tables[$tablename] = $table;
992 $DB->insert_record($tablename, array('course' => 3));
993 $DB->insert_record($tablename, array('course' => 2));
995 $this->assertTrue($record = $DB->get_record($tablename, array('id' => 2)));
997 $this->assertEqual(2, $record->course);
1000 public function test_get_record_sql() {
1002 $dbman = $DB->get_manager();
1004 $table = $this->get_test_table();
1005 $tablename = $table->getName();
1007 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1008 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1009 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1010 $dbman->create_table($table);
1011 $this->tables[$tablename] = $table;
1013 $DB->insert_record($tablename, array('course' => 3));
1014 $DB->insert_record($tablename, array('course' => 2));
1016 $this->assertTrue($record = $DB->get_record_sql("SELECT * FROM {".$tablename."} WHERE id = ?", array(2)));
1018 $this->assertEqual(2, $record->course);
1020 // backwards compatibility with $ignoremultiple
1021 $this->assertFalse(IGNORE_MISSING);
1022 $this->assertTrue(IGNORE_MULTIPLE);
1025 $this->assertFalse($record = $DB->get_record_sql("SELECT * FROM {".$tablename."} WHERE id = ?", array(666), IGNORE_MISSING));
1026 $this->assertFalse($record = $DB->get_record_sql("SELECT * FROM {".$tablename."} WHERE id = ?", array(666), IGNORE_MULTIPLE));
1028 $DB->get_record_sql("SELECT * FROM {".$tablename."} WHERE id = ?", array(666), MUST_EXIST);
1029 $this->fail("Exception expected");
1030 } catch (dml_missing_record_exception $e) {
1031 $this->assertTrue(true);
1035 ob_start(); // hide debug warning
1036 $this->assertTrue($record = $DB->get_record_sql("SELECT * FROM {".$tablename."}", array(), IGNORE_MISSING));
1038 $this->assertTrue($record = $DB->get_record_sql("SELECT * FROM {".$tablename."}", array(), IGNORE_MULTIPLE));
1040 $DB->get_record_sql("SELECT * FROM {".$tablename."}", array(), MUST_EXIST);
1041 $this->fail("Exception expected");
1042 } catch (dml_multiple_records_exception $e) {
1043 $this->assertTrue(true);
1047 public function test_get_field() {
1051 $dbman = $DB->get_manager();
1053 $table = $this->get_test_table();
1054 $tablename = $table->getName();
1056 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1057 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1058 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1059 $dbman->create_table($table);
1060 $this->tables[$tablename] = $table;
1062 $id1 = $DB->insert_record($tablename, array('course' => 3));
1063 $DB->insert_record($tablename, array('course' => 5));
1064 $DB->insert_record($tablename, array('course' => 5));
1066 $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id1)));
1067 $this->assertEqual(3, $DB->get_field($tablename, 'course', array('course' => 3)));
1069 $this->assertIdentical(false, $DB->get_field($tablename, 'course', array('course' => 11), IGNORE_MISSING));
1071 $DB->get_field($tablename, 'course', array('course' => 4), MUST_EXIST);
1072 $this->assertFail('Exception expected due to missing record');
1073 } catch (dml_exception $ex) {
1074 $this->assertTrue(true);
1077 $olddebug = $CFG->debug; // Save current debug settings
1078 $olddisplay = $CFG->debugdisplay;
1079 $CFG->debug = DEBUG_DEVELOPER;
1080 $CFG->debugdisplay = true;
1082 ob_start(); // catch debug warning
1083 $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MULTIPLE));
1084 $debuginfo = ob_get_contents();
1086 $this->assertTrue($debuginfo === '');
1088 ob_start(); // catch debug warning
1089 $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MISSING));
1090 $debuginfo = ob_get_contents();
1092 $this->assertFalse($debuginfo === '');
1094 $CFG->debug = $olddebug; // Restore original debug settings
1095 $CFG->debugdisplay = $olddisplay;
1098 public function test_get_field_select() {
1100 $dbman = $DB->get_manager();
1102 $table = $this->get_test_table();
1103 $tablename = $table->getName();
1105 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1106 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1107 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1108 $dbman->create_table($table);
1109 $this->tables[$tablename] = $table;
1111 $DB->insert_record($tablename, array('course' => 3));
1113 $this->assertTrue($course = $DB->get_field_select($tablename, 'course', "id = ?", array(1)));
1114 $this->assertEqual(3, $course);
1118 public function test_get_field_sql() {
1120 $dbman = $DB->get_manager();
1122 $table = $this->get_test_table();
1123 $tablename = $table->getName();
1125 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1126 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1127 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1128 $dbman->create_table($table);
1129 $this->tables[$tablename] = $table;
1131 $DB->insert_record($tablename, array('course' => 3));
1133 $this->assertTrue($course = $DB->get_field_sql("SELECT course FROM {".$tablename."} WHERE id = ?", array(1)));
1134 $this->assertEqual(3, $course);
1138 public function test_get_fieldset_select() {
1140 $dbman = $DB->get_manager();
1142 $table = $this->get_test_table();
1143 $tablename = $table->getName();
1145 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1146 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1147 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1148 $dbman->create_table($table);
1149 $this->tables[$tablename] = $table;
1151 $DB->insert_record($tablename, array('course' => 1));
1152 $DB->insert_record($tablename, array('course' => 3));
1153 $DB->insert_record($tablename, array('course' => 2));
1154 $DB->insert_record($tablename, array('course' => 6));
1156 $this->assertTrue($fieldset = $DB->get_fieldset_select($tablename, 'course', "course > ?", array(1)));
1158 $this->assertEqual(3, count($fieldset));
1159 $this->assertEqual(3, $fieldset[0]);
1160 $this->assertEqual(2, $fieldset[1]);
1161 $this->assertEqual(6, $fieldset[2]);
1165 public function test_get_fieldset_sql() {
1167 $dbman = $DB->get_manager();
1169 $table = $this->get_test_table();
1170 $tablename = $table->getName();
1172 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1173 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1174 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1175 $dbman->create_table($table);
1176 $this->tables[$tablename] = $table;
1178 $DB->insert_record($tablename, array('course' => 1));
1179 $DB->insert_record($tablename, array('course' => 3));
1180 $DB->insert_record($tablename, array('course' => 2));
1181 $DB->insert_record($tablename, array('course' => 6));
1183 $this->assertTrue($fieldset = $DB->get_fieldset_sql("SELECT * FROM {".$tablename."} WHERE course > ?", array(1)));
1185 $this->assertEqual(3, count($fieldset));
1186 $this->assertEqual(2, $fieldset[0]);
1187 $this->assertEqual(3, $fieldset[1]);
1188 $this->assertEqual(4, $fieldset[2]);
1191 public function test_insert_record_raw() {
1193 $dbman = $DB->get_manager();
1195 $table = $this->get_test_table();
1196 $tablename = $table->getName();
1198 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1199 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1200 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1201 $dbman->create_table($table);
1202 $this->tables[$tablename] = $table;
1204 $this->assertTrue($DB->insert_record_raw($tablename, array('course' => 1)));
1205 $this->assertTrue($record = $DB->get_record($tablename, array('course' => 1)));
1206 $this->assertEqual(1, $record->course);
1209 public function test_insert_record() {
1211 // All the information in this test is fetched from DB by get_recordset() so we
1212 // have such method properly tested against nulls, empties and friends...
1217 $dbman = $DB->get_manager();
1219 $table = $this->get_test_table();
1220 $tablename = $table->getName();
1222 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1223 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1224 $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
1225 $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1226 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1227 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1228 $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1229 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1230 $dbman->create_table($table);
1231 $this->tables[$tablename] = $table;
1233 $this->assertTrue($DB->insert_record($tablename, array('course' => 1), false)); // Without returning id
1234 $rs = $DB->get_recordset($tablename, array('course' => 1));
1235 $record = $rs->current();
1237 $this->assertEqual(1, $record->id);
1238 $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
1239 $this->assertEqual(200, $record->onenum);
1240 $this->assertEqual('onestring', $record->onechar);
1241 $this->assertNull($record->onetext);
1242 $this->assertNull($record->onebinary);
1244 // Check nulls are set properly for all types
1245 $record->oneint = null;
1246 $record->onenum = null;
1247 $record->onechar = null;
1248 $record->onetext = null;
1249 $record->onebinary = null;
1250 $recid = $DB->insert_record($tablename, $record);
1251 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1252 $record = $rs->current();
1254 $this->assertNull($record->oneint);
1255 $this->assertNull($record->onenum);
1256 $this->assertNull($record->onechar);
1257 $this->assertNull($record->onetext);
1258 $this->assertNull($record->onebinary);
1260 // Check zeros are set properly for all types
1261 $record->oneint = 0;
1262 $record->onenum = 0;
1263 $recid = $DB->insert_record($tablename, $record);
1264 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1265 $record = $rs->current();
1267 $this->assertEqual(0, $record->oneint);
1268 $this->assertEqual(0, $record->onenum);
1270 // Check booleans are set properly for all types
1271 $record->oneint = true; // trues
1272 $record->onenum = true;
1273 $record->onechar = true;
1274 $record->onetext = true;
1275 $recid = $DB->insert_record($tablename, $record);
1276 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1277 $record = $rs->current();
1279 $this->assertEqual(1, $record->oneint);
1280 $this->assertEqual(1, $record->onenum);
1281 $this->assertEqual(1, $record->onechar);
1282 $this->assertEqual(1, $record->onetext);
1284 $record->oneint = false; // falses
1285 $record->onenum = false;
1286 $record->onechar = false;
1287 $record->onetext = false;
1288 $recid = $DB->insert_record($tablename, $record);
1289 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1290 $record = $rs->current();
1292 $this->assertEqual(0, $record->oneint);
1293 $this->assertEqual(0, $record->onenum);
1294 $this->assertEqual(0, $record->onechar);
1295 $this->assertEqual(0, $record->onetext);
1297 // Check string data causes exception in numeric types
1298 $record->oneint = 'onestring';
1299 $record->onenum = 0;
1301 $DB->insert_record($tablename, $record);
1302 $this->fail("Expecting an exception, none occurred");
1303 } catch (exception $e) {
1304 $this->assertTrue($e instanceof dml_exception);
1306 $record->oneint = 0;
1307 $record->onenum = 'onestring';
1309 $DB->insert_record($tablename, $record);
1310 $this->fail("Expecting an exception, none occurred");
1311 } catch (exception $e) {
1312 $this->assertTrue($e instanceof dml_exception);
1315 // Check empty string data is stored as 0 in numeric datatypes
1316 $record->oneint = ''; // empty string
1317 $record->onenum = 0;
1318 $recid = $DB->insert_record($tablename, $record);
1319 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1320 $record = $rs->current();
1322 $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
1324 $record->oneint = 0;
1325 $record->onenum = ''; // empty string
1326 $recid = $DB->insert_record($tablename, $record);
1327 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1328 $record = $rs->current();
1330 $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
1332 // Check empty strings are set properly in string types
1333 $record->oneint = 0;
1334 $record->onenum = 0;
1335 $record->onechar = '';
1336 $record->onetext = '';
1337 $recid = $DB->insert_record($tablename, $record);
1338 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1339 $record = $rs->current();
1341 $this->assertTrue($record->onechar === '');
1342 $this->assertTrue($record->onetext === '');
1344 // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1345 $record->oneint = ((210.10 + 39.92) - 150.02);
1346 $record->onenum = ((210.10 + 39.92) - 150.02);
1347 $recid = $DB->insert_record($tablename, $record);
1348 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1349 $record = $rs->current();
1351 $this->assertEqual(100, $record->oneint);
1352 $this->assertEqual(100, $record->onenum);
1354 // Check various quotes/backslashes combinations in string types
1355 $teststrings = array(
1356 'backslashes and quotes alone (even): "" \'\' \\\\',
1357 'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1358 'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1359 'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1360 foreach ($teststrings as $teststring) {
1361 $record->onechar = $teststring;
1362 $record->onetext = $teststring;
1363 $recid = $DB->insert_record($tablename, $record);
1364 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1365 $record = $rs->current();
1367 $this->assertEqual($teststring, $record->onechar);
1368 $this->assertEqual($teststring, $record->onetext);
1371 // Check LOBs in text/binary columns
1372 $clob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/clob.txt');
1373 $blob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/randombinary');
1374 $record->onetext = $clob;
1375 $record->onebinary = $blob;
1376 $recid = $DB->insert_record($tablename, $record);
1377 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1378 $record = $rs->current();
1380 $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
1381 $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
1383 // And "small" LOBs too, just in case
1384 $newclob = substr($clob, 0, 500);
1385 $newblob = substr($blob, 0, 250);
1386 $record->onetext = $newclob;
1387 $record->onebinary = $newblob;
1388 $recid = $DB->insert_record($tablename, $record);
1389 $rs = $DB->get_recordset($tablename, array('id' => $recid));
1390 $record = $rs->current();
1392 $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
1393 $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
1394 $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
1396 // test data is not modified
1397 $rec = new object();
1398 $rec->id = -1; // has to be ignored
1400 $rec->lalala = 'lalal'; // unused
1401 $before = clone($rec);
1402 $DB->insert_record($tablename, $record);
1403 $this->assertEqual($rec, $before);
1406 public function test_import_record() {
1408 $dbman = $DB->get_manager();
1410 $table = $this->get_test_table();
1411 $tablename = $table->getName();
1413 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1414 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1415 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1416 $dbman->create_table($table);
1417 $this->tables[$tablename] = $table;
1419 $record = (object)array('id'=>666, 'course'=>10);
1420 $this->assertTrue($DB->import_record($tablename, $record));
1421 $records = $DB->get_records($tablename);
1422 $this->assertEqual(1, count($records));
1423 $this->assertEqual(10, $records[666]->course);
1425 $record = (object)array('id'=>13, 'course'=>2);
1426 $this->assertTrue($DB->import_record($tablename, $record));
1427 $records = $DB->get_records($tablename);
1428 $this->assertEqual(2, $records[13]->course);
1431 public function test_update_record_raw() {
1433 $dbman = $DB->get_manager();
1435 $table = $this->get_test_table();
1436 $tablename = $table->getName();
1438 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1439 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1440 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1441 $dbman->create_table($table);
1442 $this->tables[$tablename] = $table;
1444 $DB->insert_record($tablename, array('course' => 1));
1445 $record = $DB->get_record($tablename, array('course' => 1));
1446 $record->course = 2;
1447 $this->assertTrue($DB->update_record_raw($tablename, $record));
1448 $this->assertFalse($record = $DB->get_record($tablename, array('course' => 1)));
1449 $this->assertTrue($record = $DB->get_record($tablename, array('course' => 2)));
1452 public function test_update_record() {
1454 // All the information in this test is fetched from DB by get_record() so we
1455 // have such method properly tested against nulls, empties and friends...
1460 $dbman = $DB->get_manager();
1462 $table = $this->get_test_table();
1463 $tablename = $table->getName();
1465 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1466 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1467 $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
1468 $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1469 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1470 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1471 $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1472 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1473 $dbman->create_table($table);
1474 $this->tables[$tablename] = $table;
1476 $DB->insert_record($tablename, array('course' => 1));
1477 $record = $DB->get_record($tablename, array('course' => 1));
1478 $record->course = 2;
1480 $this->assertTrue($DB->update_record($tablename, $record));
1481 $this->assertFalse($record = $DB->get_record($tablename, array('course' => 1)));
1482 $this->assertTrue($record = $DB->get_record($tablename, array('course' => 2)));
1483 $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
1484 $this->assertEqual(200, $record->onenum);
1485 $this->assertEqual('onestring', $record->onechar);
1486 $this->assertNull($record->onetext);
1487 $this->assertNull($record->onebinary);
1489 // Check nulls are set properly for all types
1490 $record->oneint = null;
1491 $record->onenum = null;
1492 $record->onechar = null;
1493 $record->onetext = null;
1494 $record->onebinary = null;
1495 $DB->update_record($tablename, $record);
1496 $record = $DB->get_record($tablename, array('course' => 2));
1497 $this->assertNull($record->oneint);
1498 $this->assertNull($record->onenum);
1499 $this->assertNull($record->onechar);
1500 $this->assertNull($record->onetext);
1501 $this->assertNull($record->onebinary);
1503 // Check zeros are set properly for all types
1504 $record->oneint = 0;
1505 $record->onenum = 0;
1506 $DB->update_record($tablename, $record);
1507 $record = $DB->get_record($tablename, array('course' => 2));
1508 $this->assertEqual(0, $record->oneint);
1509 $this->assertEqual(0, $record->onenum);
1511 // Check booleans are set properly for all types
1512 $record->oneint = true; // trues
1513 $record->onenum = true;
1514 $record->onechar = true;
1515 $record->onetext = true;
1516 $DB->update_record($tablename, $record);
1517 $record = $DB->get_record($tablename, array('course' => 2));
1518 $this->assertEqual(1, $record->oneint);
1519 $this->assertEqual(1, $record->onenum);
1520 $this->assertEqual(1, $record->onechar);
1521 $this->assertEqual(1, $record->onetext);
1523 $record->oneint = false; // falses
1524 $record->onenum = false;
1525 $record->onechar = false;
1526 $record->onetext = false;
1527 $DB->update_record($tablename, $record);
1528 $record = $DB->get_record($tablename, array('course' => 2));
1529 $this->assertEqual(0, $record->oneint);
1530 $this->assertEqual(0, $record->onenum);
1531 $this->assertEqual(0, $record->onechar);
1532 $this->assertEqual(0, $record->onetext);
1534 // Check string data causes exception in numeric types
1535 $record->oneint = 'onestring';
1536 $record->onenum = 0;
1538 $DB->update_record($tablename, $record);
1539 $this->fail("Expecting an exception, none occurred");
1540 } catch (exception $e) {
1541 $this->assertTrue($e instanceof dml_exception);
1543 $record->oneint = 0;
1544 $record->onenum = 'onestring';
1546 $DB->update_record($tablename, $record);
1547 $this->fail("Expecting an exception, none occurred");
1548 } catch (exception $e) {
1549 $this->assertTrue($e instanceof dml_exception);
1552 // Check empty string data is stored as 0 in numeric datatypes
1553 $record->oneint = ''; // empty string
1554 $record->onenum = 0;
1555 $DB->update_record($tablename, $record);
1556 $record = $DB->get_record($tablename, array('course' => 2));
1557 $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
1559 $record->oneint = 0;
1560 $record->onenum = ''; // empty string
1561 $DB->update_record($tablename, $record);
1562 $record = $DB->get_record($tablename, array('course' => 2));
1563 $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
1565 // Check empty strings are set properly in string types
1566 $record->oneint = 0;
1567 $record->onenum = 0;
1568 $record->onechar = '';
1569 $record->onetext = '';
1570 $DB->update_record($tablename, $record);
1571 $record = $DB->get_record($tablename, array('course' => 2));
1572 $this->assertTrue($record->onechar === '');
1573 $this->assertTrue($record->onetext === '');
1575 // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1576 $record->oneint = ((210.10 + 39.92) - 150.02);
1577 $record->onenum = ((210.10 + 39.92) - 150.02);
1578 $DB->update_record($tablename, $record);
1579 $record = $DB->get_record($tablename, array('course' => 2));
1580 $this->assertEqual(100, $record->oneint);
1581 $this->assertEqual(100, $record->onenum);
1583 // Check various quotes/backslashes combinations in string types
1584 $teststrings = array(
1585 'backslashes and quotes alone (even): "" \'\' \\\\',
1586 'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1587 'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1588 'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1589 foreach ($teststrings as $teststring) {
1590 $record->onechar = $teststring;
1591 $record->onetext = $teststring;
1592 $DB->update_record($tablename, $record);
1593 $record = $DB->get_record($tablename, array('course' => 2));
1594 $this->assertEqual($teststring, $record->onechar);
1595 $this->assertEqual($teststring, $record->onetext);
1598 // Check LOBs in text/binary columns
1599 $clob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/clob.txt');
1600 $blob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/randombinary');
1601 $record->onetext = $clob;
1602 $record->onebinary = $blob;
1603 $DB->update_record($tablename, $record);
1604 $record = $DB->get_record($tablename, array('course' => 2));
1605 $this->assertEqual($clob, $record->onetext, 'Test CLOB update (full contents output disabled)');
1606 $this->assertEqual($blob, $record->onebinary, 'Test BLOB update (full contents output disabled)');
1608 // And "small" LOBs too, just in case
1609 $newclob = substr($clob, 0, 500);
1610 $newblob = substr($blob, 0, 250);
1611 $record->onetext = $newclob;
1612 $record->onebinary = $newblob;
1613 $DB->update_record($tablename, $record);
1614 $record = $DB->get_record($tablename, array('course' => 2));
1615 $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB update (full contents output disabled)');
1616 $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB update (full contents output disabled)');
1619 public function test_set_field() {
1621 $dbman = $DB->get_manager();
1623 $table = $this->get_test_table();
1624 $tablename = $table->getName();
1626 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1627 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1628 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1629 $dbman->create_table($table);
1630 $this->tables[$tablename] = $table;
1632 $DB->insert_record($tablename, array('course' => 1));
1634 $this->assertTrue($DB->set_field($tablename, 'course', 2, array('id' => 1)));
1635 $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => 1)));
1637 // Add one set_field() example where the field being set is also one condition
1638 // to check we haven't problem with any type of param (specially NAMED ones)
1639 $DB->set_field($tablename, 'course', '1', array('course' => 2));
1640 $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => 1)));
1642 // Note: All the nulls, booleans, empties, quoted and backslashes tests
1643 // go to set_field_select() because set_field() is just one wrapper over it
1646 public function test_set_field_select() {
1648 // All the information in this test is fetched from DB by get_field() so we
1649 // have such method properly tested against nulls, empties and friends...
1654 $dbman = $DB->get_manager();
1656 $table = $this->get_test_table();
1657 $tablename = $table->getName();
1659 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1660 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1661 $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null);
1662 $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null);
1663 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
1664 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1665 $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1666 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1667 $dbman->create_table($table);
1668 $this->tables[$tablename] = $table;
1670 $DB->insert_record($tablename, array('course' => 1));
1672 $this->assertTrue($DB->set_field_select($tablename, 'course', 2, 'id = ?', array(1)));
1673 $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => 1)));
1675 // Check nulls are set properly for all types
1676 $DB->set_field_select($tablename, 'oneint', null, 'id = ?', array(1)); // trues
1677 $DB->set_field_select($tablename, 'onenum', null, 'id = ?', array(1));
1678 $DB->set_field_select($tablename, 'onechar', null, 'id = ?', array(1));
1679 $DB->set_field_select($tablename, 'onetext', null, 'id = ?', array(1));
1680 $DB->set_field_select($tablename, 'onebinary', null, 'id = ?', array(1));
1681 $this->assertNull($DB->get_field($tablename, 'oneint', array('id' => 1)));
1682 $this->assertNull($DB->get_field($tablename, 'onenum', array('id' => 1)));
1683 $this->assertNull($DB->get_field($tablename, 'onechar', array('id' => 1)));
1684 $this->assertNull($DB->get_field($tablename, 'onetext', array('id' => 1)));
1685 $this->assertNull($DB->get_field($tablename, 'onebinary', array('id' => 1)));
1687 // Check zeros are set properly for all types
1688 $DB->set_field_select($tablename, 'oneint', 0, 'id = ?', array(1));
1689 $DB->set_field_select($tablename, 'onenum', 0, 'id = ?', array(1));
1690 $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
1691 $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
1693 // Check booleans are set properly for all types
1694 $DB->set_field_select($tablename, 'oneint', true, 'id = ?', array(1)); // trues
1695 $DB->set_field_select($tablename, 'onenum', true, 'id = ?', array(1));
1696 $DB->set_field_select($tablename, 'onechar', true, 'id = ?', array(1));
1697 $DB->set_field_select($tablename, 'onetext', true, 'id = ?', array(1));
1698 $this->assertEqual(1, $DB->get_field($tablename, 'oneint', array('id' => 1)));
1699 $this->assertEqual(1, $DB->get_field($tablename, 'onenum', array('id' => 1)));
1700 $this->assertEqual(1, $DB->get_field($tablename, 'onechar', array('id' => 1)));
1701 $this->assertEqual(1, $DB->get_field($tablename, 'onetext', array('id' => 1)));
1703 $DB->set_field_select($tablename, 'oneint', false, 'id = ?', array(1)); // falses
1704 $DB->set_field_select($tablename, 'onenum', false, 'id = ?', array(1));
1705 $DB->set_field_select($tablename, 'onechar', false, 'id = ?', array(1));
1706 $DB->set_field_select($tablename, 'onetext', false, 'id = ?', array(1));
1707 $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
1708 $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
1709 $this->assertEqual(0, $DB->get_field($tablename, 'onechar', array('id' => 1)));
1710 $this->assertEqual(0, $DB->get_field($tablename, 'onetext', array('id' => 1)));
1712 // Check string data causes exception in numeric types
1714 $DB->set_field_select($tablename, 'oneint', 'onestring', 'id = ?', array(1));
1715 $this->fail("Expecting an exception, none occurred");
1716 } catch (exception $e) {
1717 $this->assertTrue($e instanceof dml_exception);
1720 $DB->set_field_select($tablename, 'onenum', 'onestring', 'id = ?', array(1));
1721 $this->fail("Expecting an exception, none occurred");
1722 } catch (exception $e) {
1723 $this->assertTrue($e instanceof dml_exception);
1726 // Check empty string data is stored as 0 in numeric datatypes
1727 $DB->set_field_select($tablename, 'oneint', '', 'id = ?', array(1));
1728 $field = $DB->get_field($tablename, 'oneint', array('id' => 1));
1729 $this->assertTrue(is_numeric($field) && $field == 0);
1731 $DB->set_field_select($tablename, 'onenum', '', 'id = ?', array(1));
1732 $field = $DB->get_field($tablename, 'onenum', array('id' => 1));
1733 $this->assertTrue(is_numeric($field) && $field == 0);
1735 // Check empty strings are set properly in string types
1736 $DB->set_field_select($tablename, 'onechar', '', 'id = ?', array(1));
1737 $DB->set_field_select($tablename, 'onetext', '', 'id = ?', array(1));
1738 $this->assertTrue($DB->get_field($tablename, 'onechar', array('id' => 1)) === '');
1739 $this->assertTrue($DB->get_field($tablename, 'onetext', array('id' => 1)) === '');
1741 // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1742 $DB->set_field_select($tablename, 'oneint', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
1743 $DB->set_field_select($tablename, 'onenum', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
1744 $this->assertEqual(100, $DB->get_field($tablename, 'oneint', array('id' => 1)));
1745 $this->assertEqual(100, $DB->get_field($tablename, 'onenum', array('id' => 1)));
1747 // Check various quotes/backslashes combinations in string types
1748 $teststrings = array(
1749 'backslashes and quotes alone (even): "" \'\' \\\\',
1750 'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1751 'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1752 'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1753 foreach ($teststrings as $teststring) {
1754 $DB->set_field_select($tablename, 'onechar', $teststring, 'id = ?', array(1));
1755 $DB->set_field_select($tablename, 'onetext', $teststring, 'id = ?', array(1));
1756 $this->assertEqual($teststring, $DB->get_field($tablename, 'onechar', array('id' => 1)));
1757 $this->assertEqual($teststring, $DB->get_field($tablename, 'onetext', array('id' => 1)));
1760 // Check LOBs in text/binary columns
1761 $clob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/clob.txt');
1762 $blob = file_get_contents($CFG->libdir.'/dml/simpletest/fixtures/randombinary');
1763 $DB->set_field_select($tablename, 'onetext', $clob, 'id = ?', array(1));
1764 $DB->set_field_select($tablename, 'onebinary', $blob, 'id = ?', array(1));
1765 $this->assertEqual($clob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test CLOB set_field (full contents output disabled)');
1766 $this->assertEqual($blob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test BLOB set_field (full contents output disabled)');
1768 // And "small" LOBs too, just in case
1769 $newclob = substr($clob, 0, 500);
1770 $newblob = substr($blob, 0, 250);
1771 $DB->set_field_select($tablename, 'onetext', $newclob, 'id = ?', array(1));
1772 $DB->set_field_select($tablename, 'onebinary', $newblob, 'id = ?', array(1));
1773 $this->assertEqual($newclob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test "small" CLOB set_field (full contents output disabled)');
1774 $this->assertEqual($newblob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test "small" BLOB set_field (full contents output disabled)');
1777 public function test_count_records() {
1780 $dbman = $DB->get_manager();
1782 $table = $this->get_test_table();
1783 $tablename = $table->getName();
1785 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1786 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1787 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1788 $dbman->create_table($table);
1789 $this->tables[$tablename] = $table;
1791 $this->assertEqual(0, $DB->count_records($tablename));
1793 $DB->insert_record($tablename, array('course' => 3));
1794 $DB->insert_record($tablename, array('course' => 4));
1795 $DB->insert_record($tablename, array('course' => 5));
1797 $this->assertEqual(3, $DB->count_records($tablename));
1800 public function test_count_records_select() {
1803 $dbman = $DB->get_manager();
1805 $table = $this->get_test_table();
1806 $tablename = $table->getName();
1808 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1809 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1810 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1811 $dbman->create_table($table);
1812 $this->tables[$tablename] = $table;
1814 $this->assertEqual(0, $DB->count_records($tablename));
1816 $DB->insert_record($tablename, array('course' => 3));
1817 $DB->insert_record($tablename, array('course' => 4));
1818 $DB->insert_record($tablename, array('course' => 5));
1820 $this->assertEqual(2, $DB->count_records_select($tablename, 'course > ?', array(3)));
1823 public function test_count_records_sql() {
1825 $dbman = $DB->get_manager();
1827 $table = $this->get_test_table();
1828 $tablename = $table->getName();
1830 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1831 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1832 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1833 $dbman->create_table($table);
1834 $this->tables[$tablename] = $table;
1836 $this->assertEqual(0, $DB->count_records($tablename));
1838 $DB->insert_record($tablename, array('course' => 3));
1839 $DB->insert_record($tablename, array('course' => 4));
1840 $DB->insert_record($tablename, array('course' => 5));
1842 $this->assertEqual(2, $DB->count_records_sql("SELECT COUNT(*) FROM {".$tablename."} WHERE course > ?", array(3)));
1845 public function test_record_exists() {
1847 $dbman = $DB->get_manager();
1849 $table = $this->get_test_table();
1850 $tablename = $table->getName();
1852 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1853 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1854 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1855 $dbman->create_table($table);
1856 $this->tables[$tablename] = $table;
1858 $this->assertEqual(0, $DB->count_records($tablename));
1860 $this->assertFalse($DB->record_exists($tablename, array('course' => 3)));
1861 $DB->insert_record($tablename, array('course' => 3));
1863 $this->assertTrue($DB->record_exists($tablename, array('course' => 3)));
1867 public function test_record_exists_select() {
1869 $dbman = $DB->get_manager();
1871 $table = $this->get_test_table();
1872 $tablename = $table->getName();
1874 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1875 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1876 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1877 $dbman->create_table($table);
1878 $this->tables[$tablename] = $table;
1880 $this->assertEqual(0, $DB->count_records($tablename));
1882 $this->assertFalse($DB->record_exists_select($tablename, "course = ?", array(3)));
1883 $DB->insert_record($tablename, array('course' => 3));
1885 $this->assertTrue($DB->record_exists_select($tablename, "course = ?", array(3)));
1888 public function test_record_exists_sql() {
1890 $dbman = $DB->get_manager();
1892 $table = $this->get_test_table();
1893 $tablename = $table->getName();
1895 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1896 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1897 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1898 $dbman->create_table($table);
1899 $this->tables[$tablename] = $table;
1901 $this->assertEqual(0, $DB->count_records($tablename));
1903 $this->assertFalse($DB->record_exists_sql("SELECT * FROM {".$tablename."} WHERE course = ?", array(3)));
1904 $DB->insert_record($tablename, array('course' => 3));
1906 $this->assertTrue($DB->record_exists_sql("SELECT * FROM {".$tablename."} WHERE course = ?", array(3)));
1909 public function test_delete_records() {
1911 $dbman = $DB->get_manager();
1913 $table = $this->get_test_table();
1914 $tablename = $table->getName();
1916 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1917 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1918 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1919 $dbman->create_table($table);
1920 $this->tables[$tablename] = $table;
1922 $DB->insert_record($tablename, array('course' => 3));
1923 $DB->insert_record($tablename, array('course' => 2));
1924 $DB->insert_record($tablename, array('course' => 2));
1926 // Delete all records
1927 $this->assertTrue($DB->delete_records($tablename));
1928 $this->assertEqual(0, $DB->count_records($tablename));
1930 // Delete subset of records
1931 $DB->insert_record($tablename, array('course' => 3));
1932 $DB->insert_record($tablename, array('course' => 2));
1933 $DB->insert_record($tablename, array('course' => 2));
1935 $this->assertTrue($DB->delete_records($tablename, array('course' => 2)));
1936 $this->assertEqual(1, $DB->count_records($tablename));
1939 public function test_delete_records_select() {
1941 $dbman = $DB->get_manager();
1943 $table = $this->get_test_table();
1944 $tablename = $table->getName();
1946 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1947 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1948 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1949 $dbman->create_table($table);
1950 $this->tables[$tablename] = $table;
1952 $DB->insert_record($tablename, array('course' => 3));
1953 $DB->insert_record($tablename, array('course' => 2));
1954 $DB->insert_record($tablename, array('course' => 2));
1956 $this->assertTrue($DB->delete_records_select($tablename, 'course = ?', array(2)));
1957 $this->assertEqual(1, $DB->count_records($tablename));
1960 public function test_delete_records_list() {
1962 $dbman = $DB->get_manager();
1964 $table = $this->get_test_table();
1965 $tablename = $table->getName();
1967 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1968 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1969 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1970 $dbman->create_table($table);
1971 $this->tables[$tablename] = $table;
1973 $DB->insert_record($tablename, array('course' => 1));
1974 $DB->insert_record($tablename, array('course' => 2));
1975 $DB->insert_record($tablename, array('course' => 3));
1977 $this->assertTrue($DB->delete_records_list($tablename, 'course', array(2, 3)));
1978 $this->assertEqual(1, $DB->count_records($tablename));
1980 $this->assertTrue($DB->delete_records_list($tablename, 'course', array())); /// Must delete 0 rows without conditions. MDL-17645
1981 $this->assertEqual(1, $DB->count_records($tablename));
1984 function test_sql_null_from_clause() {
1986 $sql = "SELECT 1 AS id ".$DB->sql_null_from_clause();
1987 $this->assertEqual($DB->get_field_sql($sql), 1);
1990 function test_sql_bitand() {
1992 $sql = "SELECT ".$DB->sql_bitand(10, 3)." AS res ".$DB->sql_null_from_clause();
1993 $this->assertEqual($DB->get_field_sql($sql), 2);
1996 function test_sql_bitnot() {
1999 $not = $DB->sql_bitnot(2);
2000 $notlimited = $DB->sql_bitand($not, 7); // might be positive or negative number which can not fit into PHP INT!
2002 $sql = "SELECT $notlimited AS res ".$DB->sql_null_from_clause();
2003 $this->assertEqual($DB->get_field_sql($sql), 5);
2006 function test_sql_bitor() {
2008 $sql = "SELECT ".$DB->sql_bitor(10, 3)." AS res ".$DB->sql_null_from_clause();
2009 $this->assertEqual($DB->get_field_sql($sql), 11);
2012 function test_sql_bitxor() {
2014 $sql = "SELECT ".$DB->sql_bitxor(10, 3)." AS res ".$DB->sql_null_from_clause();
2015 $this->assertEqual($DB->get_field_sql($sql), 9);
2018 function test_sql_modulo() {
2020 $sql = "SELECT ".$DB->sql_modulo(10, 7)." AS res ".$DB->sql_null_from_clause();
2021 $this->assertEqual($DB->get_field_sql($sql), 3);
2024 function test_sql_ceil() {
2026 $sql = "SELECT ".$DB->sql_ceil(665.666)." AS res ".$DB->sql_null_from_clause();
2027 $this->assertEqual($DB->get_field_sql($sql), 666);
2030 function test_cast_char2int() {
2032 $dbman = $DB->get_manager();
2034 $table1 = $this->get_test_table("testtable1");
2035 $tablename1 = $table1->getName();
2037 $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2038 $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2039 $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2040 $dbman->create_table($table1);
2041 $this->tables[$tablename1] = $table1;
2043 $DB->insert_record($tablename1, array('name'=>'100'));
2045 $table2 = $this->get_test_table("testtable2");
2046 $tablename2 = $table2->getName();
2047 $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2048 $table2->add_field('res', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2049 $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2050 $dbman->create_table($table2);
2051 $this->tables[$table2->getName()] = $table2;
2053 $DB->insert_record($tablename2, array('res'=>100));
2056 $sql = "SELECT * FROM {".$tablename1."} t1, {".$tablename2."} t2 WHERE ".$DB->sql_cast_char2int("t1.name")." = t2.res ";
2057 $records = $DB->get_records_sql($sql);
2058 $this->assertEqual(count($records), 1);
2059 } catch (dml_exception $e) {
2060 $this->fail("No exception expected");
2064 function test_cast_char2real() {
2066 $dbman = $DB->get_manager();
2068 $table = $this->get_test_table();
2069 $tablename = $table->getName();
2071 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2072 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2073 $table->add_field('res', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null);
2074 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2075 $dbman->create_table($table);
2076 $this->tables[$tablename] = $table;
2078 $DB->insert_record($tablename, array('name'=>'10.10', 'res'=>5.1));
2079 $DB->insert_record($tablename, array('name'=>'1.10', 'res'=>666));
2080 $DB->insert_record($tablename, array('name'=>'11.10', 'res'=>0.1));
2082 $sql = "SELECT * FROM {".$tablename."} WHERE ".$DB->sql_cast_char2real('name')." > res";
2083 $records = $DB->get_records_sql($sql);
2084 $this->assertEqual(count($records), 2);
2087 function sql_compare_text() {
2089 $dbman = $DB->get_manager();
2091 $table = $this->get_test_table();
2092 $tablename = $table->getName();
2094 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2095 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2096 $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2097 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2098 $dbman->create_table($table);
2099 $this->tables[$tablename] = $table;
2101 $DB->insert_record($tablename, array('name'=>'abcd', 'description'=>'abcd'));
2102 $DB->insert_record($tablename, array('name'=>'abcdef', 'description'=>'bbcdef'));
2103 $DB->insert_record($tablename, array('name'=>'aaaabb', 'description'=>'aaaacccccccccccccccccc'));
2105 $sql = "SELECT * FROM {".$tablename."} WHERE name = ".$DB->sql_compare_text('description');
2106 $records = $DB->get_records_sql($sql);
2107 $this->assertEqual(count($records), 1);
2109 $sql = "SELECT * FROM {".$tablename."} WHERE name = ".$DB->sql_compare_text('description', 4);
2110 $records = $DB->get_records_sql($sql);
2111 $this->assertEqual(count($records), 2);
2114 function test_unique_index_collation_trouble() {
2115 // note: this is a work in progress, we should probably move this to ddl test
2118 $dbman = $DB->get_manager();
2120 $table = $this->get_test_table();
2121 $tablename = $table->getName();
2123 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2124 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2125 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2126 $table->add_index('name', XMLDB_INDEX_UNIQUE, array('name'));
2127 $dbman->create_table($table);
2128 $this->tables[$tablename] = $table;
2130 $DB->insert_record($tablename, array('name'=>'aaa'));
2133 $DB->insert_record($tablename, array('name'=>'AAA'));
2134 } catch (Exception $e) {
2135 //TODO: ignore case insensitive uniqueness problems for now
2136 //$this->fail("Unique index is case sensitive - this may cause problems in some tables");
2140 $DB->insert_record($tablename, array('name'=>'aäa'));
2141 $DB->insert_record($tablename, array('name'=>'aáa'));
2142 $this->assertTrue(true);
2143 } catch (Exception $e) {
2144 $family = $DB->get_dbfamily();
2145 if ($family === 'mysql' or $family === 'mssql') {
2146 $this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages. This is usually caused by accent insensitive default collation.");
2148 // this should not happen, PostgreSQL and Oracle do not support accent insensitive uniqueness.
2149 $this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages.");
2155 function test_sql_binary_equal() {
2157 $dbman = $DB->get_manager();
2159 $table = $this->get_test_table();
2160 $tablename = $table->getName();
2162 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2163 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2164 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2165 $dbman->create_table($table);
2166 $this->tables[$tablename] = $table;
2168 $DB->insert_record($tablename, array('name'=>'aaa'));
2169 $DB->insert_record($tablename, array('name'=>'aáa'));
2170 $DB->insert_record($tablename, array('name'=>'aäa'));
2171 $DB->insert_record($tablename, array('name'=>'bbb'));
2172 $DB->insert_record($tablename, array('name'=>'BBB'));
2174 $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('aaa'));
2175 $this->assertEqual(count($records), 1, 'SQL operator "=" is expected to be accent sensitive');
2177 $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('bbb'));
2178 $this->assertEqual(count($records), 1, 'SQL operator "=" is expected to be case sensitive');
2181 function test_sql_like() {
2183 $dbman = $DB->get_manager();
2185 $table = $this->get_test_table();
2186 $tablename = $table->getName();
2188 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2189 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2190 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2191 $dbman->create_table($table);
2192 $this->tables[$tablename] = $table;
2194 $DB->insert_record($tablename, array('name'=>'SuperDuperRecord'));
2195 $DB->insert_record($tablename, array('name'=>'Nodupor'));
2196 $DB->insert_record($tablename, array('name'=>'ouch'));
2197 $DB->insert_record($tablename, array('name'=>'ouc_'));
2198 $DB->insert_record($tablename, array('name'=>'ouc%'));
2199 $DB->insert_record($tablename, array('name'=>'aui'));
2200 $DB->insert_record($tablename, array('name'=>'aüi'));
2201 $DB->insert_record($tablename, array('name'=>'aÜi'));
2203 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false);
2204 $records = $DB->get_records_sql($sql, array("%dup_r%"));
2205 $this->assertEqual(count($records), 2);
2207 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true);
2208 $records = $DB->get_records_sql($sql, array("%dup%"));
2209 $this->assertEqual(count($records), 1);
2211 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?'); // defaults
2212 $records = $DB->get_records_sql($sql, array("%dup%"));
2213 $this->assertEqual(count($records), 1);
2215 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true);
2216 $records = $DB->get_records_sql($sql, array("ouc\\_"));
2217 $this->assertEqual(count($records), 1);
2219 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true, false, '|');
2220 $records = $DB->get_records_sql($sql, array($DB->sql_like_escape("ouc%", '|')));
2221 $this->assertEqual(count($records), 1);
2223 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true);
2224 $records = $DB->get_records_sql($sql, array('aui'));
2225 $this->assertEqual(count($records), 1);
2227 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true, true); // NOT LIKE
2228 $records = $DB->get_records_sql($sql, array("%o%"));
2229 $this->assertEqual(count($records), 3);
2231 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false, true, true); // NOT ILIKE
2232 $records = $DB->get_records_sql($sql, array("%D%"));
2233 $this->assertEqual(count($records), 6);
2235 // TODO: we do not require accent insensitivness yet, just make sure it does not throw errors
2236 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, false);
2237 $records = $DB->get_records_sql($sql, array('aui'));
2238 //$this->assertEqual(count($records), 2, 'Accent insensitive LIKE searches may not be supported in all databases, this is not a problem.');
2239 $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false, false);
2240 $records = $DB->get_records_sql($sql, array('aui'));
2241 //$this->assertEqual(count($records), 3, 'Accent insensitive LIKE searches may not be supported in all databases, this is not a problem.');
2244 function test_sql_ilike() {
2247 // note: this is deprecated, just make sure it does not throw error
2249 $dbman = $DB->get_manager();
2251 $table = $this->get_test_table();
2252 $tablename = $table->getName();
2254 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2255 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2256 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2257 $dbman->create_table($table);
2258 $this->tables[$tablename] = $table;
2260 $DB->insert_record($tablename, array('name'=>'SuperDuperRecord'));
2261 $DB->insert_record($tablename, array('name'=>'NoDupor'));
2262 $DB->insert_record($tablename, array('name'=>'ouch'));
2264 // make sure it prints debug message
2265 $olddebug = $CFG->debug; // Save current debug settings
2266 $olddisplay = $CFG->debugdisplay;
2267 $CFG->debug = DEBUG_DEVELOPER;
2268 $CFG->debugdisplay = true;
2269 ob_start(); // hide debug warning
2270 $sql = "SELECT * FROM {".$tablename."} WHERE name ".$DB->sql_ilike()." ?";
2271 $params = array("%dup_r%");
2273 $debuginfo = ob_get_contents();
2274 $CFG->debug = $olddebug; // Restore original debug settings
2275 $CFG->debugdisplay = $olddisplay;
2276 $this->assertFalse($debuginfo === '');
2278 // following must not throw exception, we ignore result
2279 $DB->get_records_sql($sql, $params);
2282 function test_sql_concat() {
2284 $dbman = $DB->get_manager();
2286 /// Testing all sort of values
2287 $sql = "SELECT ".$DB->sql_concat("?", "?", "?")." AS fullname ". $DB->sql_null_from_clause();
2288 // string, some unicode chars
2289 $params = array('name', 'áéÃóú', 'name3');
2290 $this->assertEqual('nameáéÃóúname3', $DB->get_field_sql($sql, $params));
2291 // string, spaces and numbers
2292 $params = array('name', ' ', 12345);
2293 $this->assertEqual('name 12345', $DB->get_field_sql($sql, $params));
2294 // float, empty and strings
2295 $params = array(123.45, '', 'test');
2296 $this->assertEqual('123.45test', $DB->get_field_sql($sql, $params));
2297 // float, null and strings
2298 $params = array(123.45, null, 'test');
2299 $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
2301 /// Testing fieldnames + values
2302 $table = $this->get_test_table();
2303 $tablename = $table->getName();
2305 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2306 $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2307 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2308 $dbman->create_table($table);
2309 $this->tables[$tablename] = $table;
2311 $DB->insert_record($tablename, array('description'=>'áéÃóú'));
2312 $DB->insert_record($tablename, array('description'=>'dxxx'));
2313 $DB->insert_record($tablename, array('description'=>'bcde'));
2315 $sql = 'SELECT id, ' . $DB->sql_concat('description', "'harcoded'", '?', '?') . ' AS result FROM {' . $tablename . '}';
2316 $records = $DB->get_records_sql($sql, array(123.45, 'test'));
2317 $this->assertEqual(count($records), 3);
2318 $this->assertEqual($records[1]->result, 'áéÃóúharcoded123.45test');
2321 function test_concat_join() {
2323 $sql = "SELECT ".$DB->sql_concat_join("' '", array("?", "?", "?"))." AS fullname ".$DB->sql_null_from_clause();
2324 $params = array("name", "name2", "name3");
2325 $result = $DB->get_field_sql($sql, $params);
2326 $this->assertEqual("name name2 name3", $result);
2329 function test_sql_fullname() {
2331 $sql = "SELECT ".$DB->sql_fullname(':first', ':last')." AS fullname ".$DB->sql_null_from_clause();
2332 $params = array('first'=>'Firstname', 'last'=>'Surname');
2333 $this->assertEqual("Firstname Surname", $DB->get_field_sql($sql, $params));
2336 function sql_sql_order_by_text() {
2338 $dbman = $DB->get_manager();
2340 $table = $this->get_test_table();
2341 $tablename = $table->getName();
2343 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2344 $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2345 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2346 $dbman->create_table($table);
2347 $this->tables[$tablename] = $table;
2349 $DB->insert_record($tablename, array('description'=>'abcd'));
2350 $DB->insert_record($tablename, array('description'=>'dxxx'));
2351 $DB->insert_record($tablename, array('description'=>'bcde'));
2353 $sql = "SELECT * FROM {".$tablename."} ORDER BY ".$DB->sql_order_by_text('description');
2354 $records = $DB->get_records_sql($sql);
2355 $first = array_unshift($records);
2356 $this->assertEqual(1, $first->id);
2357 $second = array_unshift($records);
2358 $this->assertEqual(3, $second->id);
2359 $last = array_unshift($records);
2360 $this->assertEqual(2, $last->id);
2363 function test_sql_substring() {
2365 $dbman = $DB->get_manager();
2367 $table = $this->get_test_table();
2368 $tablename = $table->getName();
2370 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2371 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2372 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2373 $dbman->create_table($table);
2374 $this->tables[$tablename] = $table;
2376 $string = 'abcdefghij';
2378 $DB->insert_record($tablename, array('name'=>$string));
2380 $sql = "SELECT id, ".$DB->sql_substr("name", 5)." AS name FROM {".$tablename."}";
2381 $record = $DB->get_record_sql($sql);
2382 $this->assertEqual(substr($string, 5-1), $record->name);
2384 $sql = "SELECT id, ".$DB->sql_substr("name", 5, 2)." AS name FROM {".$tablename."}";
2385 $record = $DB->get_record_sql($sql);
2386 $this->assertEqual(substr($string, 5-1, 2), $record->name);
2389 // silence php warning ;-)
2390 @$DB->sql_substr("name");
2391 $this->fail("Expecting an exception, none occurred");
2392 } catch (Exception $e) {
2393 $this->assertTrue($e instanceof coding_exception);
2397 function test_sql_length() {
2399 $this->assertEqual($DB->get_field_sql(
2400 "SELECT ".$DB->sql_length("'aeiou'").$DB->sql_null_from_clause()), 5);
2401 $this->assertEqual($DB->get_field_sql(
2402 "SELECT ".$DB->sql_length("'áéÃóú'").$DB->sql_null_from_clause()), 5);
2405 function test_sql_position() {
2407 $this->assertEqual($DB->get_field_sql(
2408 "SELECT ".$DB->sql_position("'ood'", "'Moodle'").$DB->sql_null_from_clause()), 2);
2409 $this->assertEqual($DB->get_field_sql(
2410 "SELECT ".$DB->sql_position("'Oracle'", "'Moodle'").$DB->sql_null_from_clause()), 0);
2413 function test_sql_empty() {
2415 $dbman = $DB->get_manager();
2417 $table = $this->get_test_table();
2418 $tablename = $table->getName();
2420 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2421 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2422 $table->add_field('namenotnull', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'default value');
2423 $table->add_field('namenotnullnodeflt', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2424 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2425 $dbman->create_table($table);
2426 $this->tables[$tablename] = $table;
2428 $DB->insert_record($tablename, array('name'=>'', 'namenotnull'=>''));
2429 $DB->insert_record($tablename, array('name'=>null));
2430 $DB->insert_record($tablename, array('name'=>'lalala'));
2431 $DB->insert_record($tablename, array('name'=>0));
2433 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE name = '".$DB->sql_empty()."'");
2434 $this->assertEqual(count($records), 1);
2435 $record = reset($records);
2436 $this->assertEqual($record->name, '');
2438 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE namenotnull = '".$DB->sql_empty()."'");
2439 $this->assertEqual(count($records), 1);
2440 $record = reset($records);
2441 $this->assertEqual($record->namenotnull, '');
2443 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE namenotnullnodeflt = '".$DB->sql_empty()."'");
2444 $this->assertEqual(count($records), 4);
2445 $record = reset($records);
2446 $this->assertEqual($record->namenotnullnodeflt, '');
2449 function test_sql_isempty() {
2451 $dbman = $DB->get_manager();
2453 $table = $this->get_test_table();
2454 $tablename = $table->getName();
2456 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2457 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2458 $table->add_field('namenull', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2459 $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null);
2460 $table->add_field('descriptionnull', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2461 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2462 $dbman->create_table($table);
2463 $this->tables[$tablename] = $table;
2465 $DB->insert_record($tablename, array('name'=>'', 'namenull'=>'', 'description'=>'', 'descriptionnull'=>''));
2466 $DB->insert_record($tablename, array('name'=>'??', 'namenull'=>null, 'description'=>'??', 'descriptionnull'=>null));
2467 $DB->insert_record($tablename, array('name'=>'la', 'namenull'=>'la', 'description'=>'la', 'descriptionnull'=>'lalala'));
2468 $DB->insert_record($tablename, array('name'=>0, 'namenull'=>0, 'description'=>0, 'descriptionnull'=>0));
2470 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isempty($tablename, 'name', false, false));
2471 $this->assertEqual(count($records), 1);
2472 $record = reset($records);
2473 $this->assertEqual($record->name, '');
2475 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isempty($tablename, 'namenull', true, false));
2476 $this->assertEqual(count($records), 1);
2477 $record = reset($records);
2478 $this->assertEqual($record->namenull, '');
2480 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isempty($tablename, 'description', false, true));
2481 $this->assertEqual(count($records), 1);
2482 $record = reset($records);
2483 $this->assertEqual($record->description, '');
2485 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isempty($tablename, 'descriptionnull', true, true));
2486 $this->assertEqual(count($records), 1);
2487 $record = reset($records);
2488 $this->assertEqual($record->descriptionnull, '');
2491 function test_sql_isnotempty() {
2493 $dbman = $DB->get_manager();
2495 $table = $this->get_test_table();
2496 $tablename = $table->getName();
2498 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2499 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
2500 $table->add_field('namenull', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2501 $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null);
2502 $table->add_field('descriptionnull', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
2503 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2504 $dbman->create_table($table);
2505 $this->tables[$tablename] = $table;
2507 $DB->insert_record($tablename, array('name'=>'', 'namenull'=>'', 'description'=>'', 'descriptionnull'=>''));
2508 $DB->insert_record($tablename, array('name'=>'??', 'namenull'=>null, 'description'=>'??', 'descriptionnull'=>null));
2509 $DB->insert_record($tablename, array('name'=>'la', 'namenull'=>'la', 'description'=>'la', 'descriptionnull'=>'lalala'));
2510 $DB->insert_record($tablename, array('name'=>0, 'namenull'=>0, 'description'=>0, 'descriptionnull'=>0));
2512 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isnotempty($tablename, 'name', false, false));
2513 $this->assertEqual(count($records), 3);
2514 $record = reset($records);
2515 $this->assertEqual($record->name, '??');
2517 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isnotempty($tablename, 'namenull', true, false));
2518 $this->assertEqual(count($records), 2); // nulls aren't comparable (so they aren't "not empty"). SQL expected behaviour
2519 $record = reset($records);
2520 $this->assertEqual($record->namenull, 'la'); // so 'la' is the first non-empty 'namenull' record
2522 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isnotempty($tablename, 'description', false, true));
2523 $this->assertEqual(count($records), 3);
2524 $record = reset($records);
2525 $this->assertEqual($record->description, '??');
2527 $records = $DB->get_records_sql("SELECT * FROM {".$tablename."} WHERE ".$DB->sql_isnotempty($tablename, 'descriptionnull', true, true));
2528 $this->assertEqual(count($records), 2); // nulls aren't comparable (so they aren't "not empty"). SQL expected behaviour
2529 $record = reset($records);
2530 $this->assertEqual($record->descriptionnull, 'lalala'); // so 'lalala' is the first non-empty 'descriptionnull' record
2533 function test_sql_regex() {
2535 $dbman = $DB->get_manager();
2537 $table = $this->get_test_table();
2538 $tablename = $table->getName();
2540 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2541 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2542 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2543 $dbman->create_table($table);
2544 $this->tables[$tablename] = $table;
2546 $DB->insert_record($tablename, array('name'=>'lalala'));
2547 $DB->insert_record($tablename, array('name'=>'holaaa'));
2548 $DB->insert_record($tablename, array('name'=>'aouch'));
2550 $sql = "SELECT * FROM {".$tablename."} WHERE name ".$DB->sql_regex()." ?";
2551 $params = array('a$');
2552 if ($DB->sql_regex_supported()) {
2553 $records = $DB->get_records_sql($sql, $params);
2554 $this->assertEqual(count($records), 2);
2556 $this->assertTrue(true, 'Regexp operations not supported. Test skipped');
2559 $sql = "SELECT * FROM {".$tablename."} WHERE name ".$DB->sql_regex(false)." ?";
2560 $params = array('.a');
2561 if ($DB->sql_regex_supported()) {
2562 $records = $DB->get_records_sql($sql, $params);
2563 $this->assertEqual(count($records), 1);
2565 $this->assertTrue(true, 'Regexp operations not supported. Test skipped');
2571 * Test some more complex SQL syntax which moodle uses and depends on to work
2572 * useful to determine if new database libraries can be supported.
2574 public function test_get_records_sql_complicated() {
2577 $dbman = $DB->get_manager();
2579 $table = $this->get_test_table();
2580 $tablename = $table->getName();
2582 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2583 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2584 $table->add_field('content', XMLDB_TYPE_TEXT, 'big', XMLDB_UNSIGNED, XMLDB_NOTNULL);
2585 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2586 $dbman->create_table($table);
2587 $this->tables[$tablename] = $table;
2589 $DB->insert_record($tablename, array('course' => 3, 'content' => 'hello'));
2590 $DB->insert_record($tablename, array('course' => 3, 'content' => 'world'));
2591 $DB->insert_record($tablename, array('course' => 5, 'content' => 'hello'));
2592 $DB->insert_record($tablename, array('course' => 2, 'content' => 'universe'));
2594 // we have sql like this in moodle, this syntax breaks on older versions of sqlite for example..
2595 $sql = 'SELECT a.id AS id, a.course AS course
2596 FROM {'.$tablename.'} a
2597 JOIN (SELECT * FROM {'.$tablename.'}) b
2599 WHERE a.course = ?';
2601 $this->assertTrue($records = $DB->get_records_sql($sql, array(3)));
2602 $this->assertEqual(2, count($records));
2603 $this->assertEqual(1, reset($records)->id);
2604 $this->assertEqual(2, next($records)->id);
2606 // try embeding sql_xxxx() helper functions, to check they don't break params/binding
2607 $count = $DB->count_records($tablename, array('course' => 3, $DB->sql_compare_text('content') => 'hello'));
2608 $this->assertEqual(1, $count);
2611 function test_onelevel_commit() {
2613 $dbman = $DB->get_manager();
2615 $table = $this->get_test_table();
2616 $tablename = $table->getName();
2618 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2619 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2620 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2621 $dbman->create_table($table);
2622 $this->tables[$tablename] = $table;
2624 $transaction = $DB->start_delegated_transaction();
2625 $data = (object)array('course'=>3);
2626 $this->assertEqual(0, $DB->count_records($tablename));
2627 $DB->insert_record($tablename, $data);
2628 $this->assertEqual(1, $DB->count_records($tablename));
2629 $transaction->allow_commit();
2630 $this->assertEqual(1, $DB->count_records($tablename));
2633 function test_onelevel_rollback() {
2635 $dbman = $DB->get_manager();
2637 $table = $this->get_test_table();
2638 $tablename = $table->getName();
2640 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2641 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2642 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2643 $dbman->create_table($table);
2644 $this->tables[$tablename] = $table;
2646 // this might in fact encourage ppl to migrate from myisam to innodb
2648 $transaction = $DB->start_delegated_transaction();
2649 $data = (object)array('course'=>3);
2650 $this->assertEqual(0, $DB->count_records($tablename));
2651 $DB->insert_record($tablename, $data);
2652 $this->assertEqual(1, $DB->count_records($tablename));
2654 $transaction->rollback(new Exception('test'));
2655 $this->fail('transaction rollback must rethrow exception');
2656 } catch (Exception $e) {
2658 $this->assertEqual(0, $DB->count_records($tablename));
2661 function test_nested_transactions() {
2663 $dbman = $DB->get_manager();
2665 $table = $this->get_test_table();
2666 $tablename = $table->getName();
2668 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2669 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2670 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2671 $dbman->create_table($table);
2672 $this->tables[$tablename] = $table;
2675 $this->assertFalse($DB->is_transaction_started());
2676 $transaction1 = $DB->start_delegated_transaction();
2677 $this->assertTrue($DB->is_transaction_started());
2678 $data = (object)array('course'=>3);
2679 $DB->insert_record($tablename, $data);
2680 $transaction2 = $DB->start_delegated_transaction();
2681 $data = (object)array('course'=>4);
2682 $DB->insert_record($tablename, $data);
2683 $transaction2->allow_commit();
2684 $this->assertTrue($DB->is_transaction_started());
2685 $transaction1->allow_commit();
2686 $this->assertFalse($DB->is_transaction_started());
2687 $this->assertEqual(2, $DB->count_records($tablename));
2689 $DB->delete_records($tablename);
2691 // rollback from top level
2692 $transaction1 = $DB->start_delegated_transaction();
2693 $data = (object)array('course'=>3);
2694 $DB->insert_record($tablename, $data);
2695 $transaction2 = $DB->start_delegated_transaction();
2696 $data = (object)array('course'=>4);
2697 $DB->insert_record($tablename, $data);
2698 $transaction2->allow_commit();
2700 $transaction1->rollback(new Exception('test'));
2701 $this->fail('transaction rollback must rethrow exception');
2702 } catch (Exception $e) {
2703 $this->assertEqual(get_class($e), 'Exception');
2705 $this->assertEqual(0, $DB->count_records($tablename));
2707 $DB->delete_records($tablename);
2709 // rollback from nested level
2710 $transaction1 = $DB->start_delegated_transaction();
2711 $data = (object)array('course'=>3);
2712 $DB->insert_record($tablename, $data);
2713 $transaction2 = $DB->start_delegated_transaction();
2714 $data = (object)array('course'=>4);
2715 $DB->insert_record($tablename, $data);
2717 $transaction2->rollback(new Exception('test'));
2718 $this->fail('transaction rollback must rethrow exception');
2719 } catch (Exception $e) {
2720 $this->assertEqual(get_class($e), 'Exception');
2722 $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet
2724 $transaction1->allow_commit();
2725 } catch (Exception $e) {
2726 $this->assertEqual(get_class($e), 'dml_transaction_exception');
2728 $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet
2729 // the forced rollback is done from the default_exception handler and similar places,
2730 // let's do it manually here
2731 $this->assertTrue($DB->is_transaction_started());
2732 $DB->force_transaction_rollback();
2733 $this->assertFalse($DB->is_transaction_started());
2734 $this->assertEqual(0, $DB->count_records($tablename)); // finally rolled back
2736 $DB->delete_records($tablename);
2739 function test_transactions_forbidden() {
2741 $dbman = $DB->get_manager();
2743 $table = $this->get_test_table();
2744 $tablename = $table->getName();
2746 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2747 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2748 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2749 $dbman->create_table($table);
2750 $this->tables[$tablename] = $table;
2752 $DB->transactions_forbidden();
2753 $transaction = $DB->start_delegated_transaction();
2754 $data = (object)array('course'=>1);
2755 $DB->insert_record($tablename, $data);
2757 $DB->transactions_forbidden();
2758 } catch (Exception $e) {
2759 $this->assertEqual(get_class($e), 'dml_transaction_exception');
2761 // the previous test does not force rollback
2762 $transaction->allow_commit();
2763 $this->assertFalse($DB->is_transaction_started());
2764 $this->assertEqual(1, $DB->count_records($tablename));
2767 function test_wrong_transactions() {
2769 $dbman = $DB->get_manager();
2771 $table = $this->get_test_table();
2772 $tablename = $table->getName();
2774 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2775 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2776 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2777 $dbman->create_table($table);
2778 $this->tables[$tablename] = $table;
2781 // wrong order of nested commits
2782 $transaction1 = $DB->start_delegated_transaction();
2783 $data = (object)array('course'=>3);
2784 $DB->insert_record($tablename, $data);
2785 $transaction2 = $DB->start_delegated_transaction();
2786 $data = (object)array('course'=>4);
2787 $DB->insert_record($tablename, $data);
2789 $transaction1->allow_commit();
2790 $this->fail('wrong order of commits must throw exception');
2791 } catch (Exception $e) {
2792 $this->assertEqual(get_class($e), 'dml_transaction_exception');
2795 $transaction2->allow_commit();
2796 $this->fail('first wrong commit forces rollback');
2797 } catch (Exception $e) {
2798 $this->assertEqual(get_class($e), 'dml_transaction_exception');
2800 // this is done in default exception handler usually
2801 $this->assertTrue($DB->is_transaction_started());
2802 $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet
2803 $DB->force_transaction_rollback();
2804 $this->assertEqual(0, $DB->count_records($tablename));
2805 $DB->delete_records($tablename);
2808 // wrong order of nested rollbacks
2809 $transaction1 = $DB->start_delegated_transaction();
2810 $data = (object)array('course'=>3);
2811 $DB->insert_record($tablename, $data);
2812 $transaction2 = $DB->start_delegated_transaction();
2813 $data = (object)array('course'=>4);
2814 $DB->insert_record($tablename, $data);
2816 // this first rollback should prevent all otehr rollbacks
2817 $transaction1->rollback(new Exception('test'));
2818 } catch (Exception $e) {
2819 $this->assertEqual(get_class($e), 'Exception');
2822 $transaction2->rollback(new Exception('test'));
2823 } catch (Exception $e) {
2824 $this->assertEqual(get_class($e), 'Exception');
2827 $transaction1->rollback(new Exception('test'));
2828 } catch (Exception $e) {
2829 // the rollback was used already once, no way to use it again
2830 $this->assertEqual(get_class($e), 'dml_transaction_exception');
2832 // this is done in default exception handler usually
2833 $this->assertTrue($DB->is_transaction_started());
2834 $DB->force_transaction_rollback();
2835 $DB->delete_records($tablename);
2838 // unknown transaction object
2839 $transaction1 = $DB->start_delegated_transaction();
2840 $data = (object)array('course'=>3);
2841 $DB->insert_record($tablename, $data);
2842 $transaction2 = new moodle_transaction($DB);
2844 $transaction2->allow_commit();
2845 $this->fail('foreign transaction must fail');
2846 } catch (Exception $e) {
2847 $this->assertEqual(get_class($e), 'dml_transaction_exception');
2850 $transaction1->allow_commit();
2851 $this->fail('first wrong commit forces rollback');
2852 } catch (Exception $e) {
2853 $this->assertEqual(get_class($e), 'dml_transaction_exception');
2855 $DB->force_transaction_rollback();
2856 $DB->delete_records($tablename);
2859 function test_concurent_transactions() {
2860 // Notes about this test:
2861 // 1- MySQL needs to use one engine with transactions support (InnoDB).
2862 // 2- MSSQL needs to have enabled versioning for read committed
2863 // transactions (ALTER DATABASE xxx SET READ_COMMITTED_SNAPSHOT ON)
2865 $dbman = $DB->get_manager();
2867 $table = $this->get_test_table();
2868 $tablename = $table->getName();
2870 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2871 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2872 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2873 $dbman->create_table($table);
2874 $this->tables[$tablename] = $table;
2876 $transaction = $DB->start_delegated_transaction();
2877 $data = (object)array('course'=>1);
2878 $this->assertEqual(0, $DB->count_records($tablename));
2879 $DB->insert_record($tablename, $data);
2880 $this->assertEqual(1, $DB->count_records($tablename));
2882 //open second connection
2883 $cfg = $DB->export_dbconfig();
2884 if (!isset($cfg->dboptions)) {
2885 $cfg->dboptions = array();
2887 $DB2 = moodle_database::get_driver_instance($cfg->dbtype, $cfg->dblibrary);
2888 $DB2->connect($cfg->dbhost, $cfg->dbuser, $cfg->dbpass, $cfg->dbname, $cfg->prefix, $cfg->dboptions);
2890 // second instance should not see pending inserts
2891 $this->assertEqual(0, $DB2->count_records($tablename));
2892 $data = (object)array('course'=>2);
2893 $DB2->insert_record($tablename, $data);
2894 $this->assertEqual(1, $DB2->count_records($tablename));
2896 // first should see the changes done from second
2897 $this->assertEqual(2, $DB->count_records($tablename));
2899 // now commit and we should see it finally in second connections
2900 $transaction->allow_commit();
2901 $this->assertEqual(2, $DB2->count_records($tablename));
2906 public function test_bound_param_types() {
2908 $dbman = $DB->get_manager();
2910 $table = $this->get_test_table();
2911 $tablename = $table->getName();
2913 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2914 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
2915 $table->add_field('content', XMLDB_TYPE_TEXT, 'big', XMLDB_UNSIGNED, XMLDB_NOTNULL);
2916 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2917 $dbman->create_table($table);
2918 $this->tables[$tablename] = $table;
2920 $this->assertTrue($DB->insert_record($tablename, array('name' => '1', 'content'=>'xx')));
2921 $this->assertTrue($DB->insert_record($tablename, array('name' => 2, 'content'=>'yy')));
2922 $this->assertTrue($DB->insert_record($tablename, array('name' => 'somestring', 'content'=>'zz')));
2923 $this->assertTrue($DB->insert_record($tablename, array('name' => 'aa', 'content'=>'1')));
2924 $this->assertTrue($DB->insert_record($tablename, array('name' => 'bb', 'content'=>2)));
2925 $this->assertTrue($DB->insert_record($tablename, array('name' => 'cc', 'content'=>'sometext')));
2928 // Conditions in CHAR columns
2929 $this->assertTrue($DB->record_exists($tablename, array('name'=>1)));
2930 $this->assertTrue($DB->record_exists($tablename, array('name'=>'1')));
2931 $this->assertFalse($DB->record_exists($tablename, array('name'=>111)));
2932 $this->assertTrue($DB->get_record($tablename, array('name'=>1)));
2933 $this->assertTrue($DB->get_record($tablename, array('name'=>'1')));
2934 $this->assertFalse($DB->get_record($tablename, array('name'=>111)));
2938 $this->assertTrue($records = $DB->get_records_sql($sqlqm, array(1)));
2939 $this->assertEqual(1, count($records));
2940 $this->assertTrue($records = $DB->get_records_sql($sqlqm, array('1')));
2941 $this->assertEqual(1, count($records));
2942 $records = $DB->get_records_sql($sqlqm, array(222));
2943 $this->assertEqual(0, count($records));
2944 $sqlnamed = "SELECT *
2946 WHERE name = :name";
2947 $this->assertTrue($records = $DB->get_records_sql($sqlnamed, array('name' => 2)));
2948 $this->assertEqual(1, count($records));
2949 $this->assertTrue($records = $DB->get_records_sql($sqlnamed, array('name' => '2')));
2950 $this->assertEqual(1, count($records));
2952 // Conditions in TEXT columns always must be performed with the sql_compare_text
2953 // helper function on both sides of the condition
2956 WHERE " . $DB->sql_compare_text('content') . " = " . $DB->sql_compare_text('?');
2957 $this->assertTrue($records = $DB->get_records_sql($sqlqm, array('1')));
2958 $this->assertEqual(1, count($records));
2959 $this->assertTrue($records = $DB->get_records_sql($sqlqm, array(1)));
2960 $this->assertEqual(1, count($records));
2961 $sqlnamed = "SELECT *
2963 WHERE " . $DB->sql_compare_text('content') . " = " . $DB->sql_compare_text(':content');
2964 $this->assertTrue($records = $DB->get_records_sql($sqlnamed, array('content' => 2)));
2965 $this->assertEqual(1, count($records));
2966 $this->assertTrue($records = $DB->get_records_sql($sqlnamed, array('content' => '2')));
2967 $this->assertEqual(1, count($records));
2972 * This class is not a proper subclass of moodle_database. It is
2973 * intended to be used only in unit tests, in order to gain access to the
2974 * protected methods of moodle_database, and unit test them.
2976 class moodle_database_for_testing extends moodle_database {
2977 protected $prefix = 'mdl_';
2979 public function public_fix_table_names($sql) {
2980 return $this->fix_table_names($sql);
2983 public function driver_installed(){}
2984 public function get_dbfamily(){}
2985 protected function get_dbtype(){}
2986 protected function get_dblibrary(){}
2987 public function get_name(){}
2988 public function get_configuration_help(){}
2989 public function get_configuration_hints(){}
2990 public function connect($dbhost, $dbuser, $dbpass, $dbname, $prefix, array $dboptions=null){}
2991 public function get_server_info(){}
2992 protected function allowed_param_types(){}
2993 public function get_last_error(){}
2994 public function get_tables($usecache=true){}
2995 public function get_indexes($table){}
2996 public function get_columns($table, $usecache=true){}
2997 protected function normalise_value($column, $value){}
2998 public function set_debug($state){}
2999 public function get_debug(){}
3000 public function set_logging($state){}
3001 public function change_database_structure($sql){}
3002 public function execute($sql, array $params=null){}
3003 public function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0){}
3004 public function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnum=0){}
3005 public function get_fieldset_sql($sql, array $params=null){}
3006 public function insert_record_raw($table, $params, $returnid=true, $bulk=false, $customsequence=false){}
3007 public function insert_record($table, $dataobject, $returnid=true, $bulk=false){}
3008 public function import_record($table, $dataobject){}
3009 public function update_record_raw($table, $params, $bulk=false){}
3010 public function update_record($table, $dataobject, $bulk=false){}
3011 public function set_field_select($table, $newfield, $newvalue, $select, array $params=null){}
3012 public function delete_records_select($table, $select, array $params=null){}
3013 public function sql_concat(){}
3014 public function sql_concat_join($separator="' '", $elements=array()){}
3015 public function sql_substr($expr, $start, $length=false){}
3016 public function begin_transaction() {}
3017 public function commit_transaction() {}
3018 public function rollback_transaction() {}