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