MDL-29295 do not use strtok in dml and ddl layers
[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_key('primary', XMLDB_KEY_PRIMARY, array('id'));
731         $dbman->create_table($table);
733         $columns = $DB->get_columns($tablename);
734         $this->assertTrue(is_array($columns));
736         $fields = $table->getFields();
737         $this->assertEqual(count($columns), count($fields));
739         $field = $columns['id'];
740         $this->assertEqual('R', $field->meta_type);
741         $this->assertTrue($field->auto_increment);
742         $this->assertTrue($field->unique);
744         $field = $columns['course'];
745         $this->assertEqual('I', $field->meta_type);
746         $this->assertFalse($field->auto_increment);
747         $this->assertTrue($field->has_default);
748         $this->assertEqual(0, $field->default_value);
749         $this->assertTrue($field->not_null);
751         $field = $columns['name'];
752         $this->assertEqual('C', $field->meta_type);
753         $this->assertFalse($field->auto_increment);
754         $this->assertTrue($field->has_default);
755         $this->assertIdentical('lala', $field->default_value);
756         $this->assertFalse($field->not_null);
758         $field = $columns['description'];
759         $this->assertEqual('X', $field->meta_type);
760         $this->assertFalse($field->auto_increment);
761         $this->assertFalse($field->has_default);
762         $this->assertIdentical(null, $field->default_value);
763         $this->assertFalse($field->not_null);
765         $field = $columns['enumfield'];
766         $this->assertEqual('C', $field->meta_type);
767         $this->assertFalse($field->auto_increment);
768         $this->assertIdentical('test2', $field->default_value);
769         $this->assertTrue($field->not_null);
771         $field = $columns['onenum'];
772         $this->assertEqual('N', $field->meta_type);
773         $this->assertFalse($field->auto_increment);
774         $this->assertTrue($field->has_default);
775         $this->assertEqual(200.0, $field->default_value);
776         $this->assertFalse($field->not_null);
778         for ($i = 0; $i < count($columns); $i++) {
779             if ($i == 0) {
780                 $next_column = reset($columns);
781                 $next_field  = reset($fields);
782             } else {
783                 $next_column = next($columns);
784                 $next_field  = next($fields);
785             }
787             $this->assertEqual($next_column->name, $next_field->name);
788         }
789     }
791     public function test_get_manager() {
792         $DB = $this->tdb;
793         $dbman = $this->tdb->get_manager();
795         $this->assertTrue($dbman instanceof database_manager);
796     }
798     public function test_setup_is_unicodedb() {
799         $DB = $this->tdb;
800         $this->assertTrue($DB->setup_is_unicodedb());
801     }
803     public function test_set_debug() { //tests get_debug() too
804         $DB = $this->tdb;
805         $dbman = $this->tdb->get_manager();
807         $table = $this->get_test_table();
808         $tablename = $table->getName();
810         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
811         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
812         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
813         $dbman->create_table($table);
815         $sql = "SELECT * FROM {{$tablename}}";
817         $prevdebug = $DB->get_debug();
819         ob_start();
820         $DB->set_debug(true);
821         $this->assertTrue($DB->get_debug());
822         $DB->execute($sql);
823         $DB->set_debug(false);
824         $this->assertFalse($DB->get_debug());
825         $debuginfo = ob_get_contents();
826         ob_end_clean();
827         $this->assertFalse($debuginfo === '');
829         ob_start();
830         $DB->execute($sql);
831         $debuginfo = ob_get_contents();
832         ob_end_clean();
833         $this->assertTrue($debuginfo === '');
835         $DB->set_debug($prevdebug);
836     }
838     public function test_execute() {
839         $DB = $this->tdb;
840         $dbman = $this->tdb->get_manager();
842         $table1 = $this->get_test_table('1');
843         $tablename1 = $table1->getName();
844         $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
845         $table1->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
846         $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
847         $table1->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
848         $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
849         $dbman->create_table($table1);
851         $table2 = $this->get_test_table('2');
852         $tablename2 = $table2->getName();
853         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
854         $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
855         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
856         $dbman->create_table($table2);
858         $DB->insert_record($tablename1, array('course' => 3, 'name' => 'aaa'));
859         $DB->insert_record($tablename1, array('course' => 1, 'name' => 'bbb'));
860         $DB->insert_record($tablename1, array('course' => 7, 'name' => 'ccc'));
861         $DB->insert_record($tablename1, array('course' => 3, 'name' => 'ddd'));
863         // select results are ignored
864         $sql = "SELECT * FROM {{$tablename1}} WHERE course = :course";
865         $this->assertTrue($DB->execute($sql, array('course'=>3)));
867         // throw exception on error
868         $sql = "XXUPDATE SET XSSD";
869         try {
870             $DB->execute($sql);
871             $this->fail("Expecting an exception, none occurred");
872         } catch (Exception $e) {
873             $this->assertTrue($e instanceof dml_write_exception);
874         }
876         // update records
877         $sql = "UPDATE {{$tablename1}}
878                    SET course = 6
879                  WHERE course = ?";
880         $this->assertTrue($DB->execute($sql, array('3')));
881         $this->assertEqual($DB->count_records($tablename1, array('course' => 6)), 2);
883         // insert from one into second table
884         $sql = "INSERT INTO {{$tablename2}} (course)
886                 SELECT course
887                   FROM {{$tablename1}}";
888         $this->assertTrue($DB->execute($sql));
889         $this->assertEqual($DB->count_records($tablename2), 4);
890     }
892     public function test_get_recordset() {
893         $DB = $this->tdb;
894         $dbman = $DB->get_manager();
896         $table = $this->get_test_table();
897         $tablename = $table->getName();
899         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
900         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
901         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
902         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
903         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
904         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
905         $dbman->create_table($table);
907         $data = array(array('id' => 1, 'course' => 3, 'name' => 'record1', 'onetext'=>'abc'),
908                       array('id' => 2, 'course' => 3, 'name' => 'record2', 'onetext'=>'abcd'),
909                       array('id' => 3, 'course' => 5, 'name' => 'record3', 'onetext'=>'abcde'));
911         foreach ($data as $record) {
912             $DB->insert_record($tablename, $record);
913         }
915         // standard recordset iteration
916         $rs = $DB->get_recordset($tablename);
917         $this->assertTrue($rs instanceof moodle_recordset);
918         reset($data);
919         foreach($rs as $record) {
920             $data_record = current($data);
921             foreach ($record as $k => $v) {
922                 $this->assertEqual($data_record[$k], $v);
923             }
924             next($data);
925         }
926         $rs->close();
928         // iterator style usage
929         $rs = $DB->get_recordset($tablename);
930         $this->assertTrue($rs instanceof moodle_recordset);
931         reset($data);
932         while ($rs->valid()) {
933             $record = $rs->current();
934             $data_record = current($data);
935             foreach ($record as $k => $v) {
936                 $this->assertEqual($data_record[$k], $v);
937             }
938             next($data);
939             $rs->next();
940         }
941         $rs->close();
943         // make sure rewind is ignored
944         $rs = $DB->get_recordset($tablename);
945         $this->assertTrue($rs instanceof moodle_recordset);
946         reset($data);
947         $i = 0;
948         foreach($rs as $record) {
949             $i++;
950             $rs->rewind();
951             if ($i > 10) {
952                 $this->fail('revind not ignored in recordsets');
953                 break;
954             }
955             $data_record = current($data);
956             foreach ($record as $k => $v) {
957                 $this->assertEqual($data_record[$k], $v);
958             }
959             next($data);
960         }
961         $rs->close();
963         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
964         $conditions = array('onetext' => '1');
965         try {
966             $rs = $DB->get_recordset($tablename, $conditions);
967             $this->fail('An Exception is missing, expected due to equating of text fields');
968         } catch (exception $e) {
969             $this->assertTrue($e instanceof dml_exception);
970             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
971         }
973         // notes:
974         //  * limits are tested in test_get_recordset_sql()
975         //  * where_clause() is used internally and is tested in test_get_records()
976     }
978     public function test_get_recordset_iterator_keys() {
979         $DB = $this->tdb;
980         $dbman = $DB->get_manager();
982         $table = $this->get_test_table();
983         $tablename = $table->getName();
985         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
986         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
987         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
988         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
989         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
990         $dbman->create_table($table);
992         $data = array(array('id'=> 1, 'course' => 3, 'name' => 'record1'),
993                       array('id'=> 2, 'course' => 3, 'name' => 'record2'),
994                       array('id'=> 3, 'course' => 5, 'name' => 'record3'));
995         foreach ($data as $record) {
996             $DB->insert_record($tablename, $record);
997         }
999         // Test repeated numeric keys are returned ok
1000         $rs = $DB->get_recordset($tablename, NULL, NULL, 'course, name, id');
1002         reset($data);
1003         $count = 0;
1004         foreach($rs as $key => $record) {
1005             $data_record = current($data);
1006             $this->assertEqual($data_record['course'], $key);
1007             next($data);
1008             $count++;
1009         }
1010         $rs->close();
1011         $this->assertEqual($count, 3);
1013         // Test string keys are returned ok
1014         $rs = $DB->get_recordset($tablename, NULL, NULL, 'name, course, id');
1016         reset($data);
1017         $count = 0;
1018         foreach($rs as $key => $record) {
1019             $data_record = current($data);
1020             $this->assertEqual($data_record['name'], $key);
1021             next($data);
1022             $count++;
1023         }
1024         $rs->close();
1025         $this->assertEqual($count, 3);
1027         // Test numeric not starting in 1 keys are returned ok
1028         $rs = $DB->get_recordset($tablename, NULL, 'id DESC', 'id, course, name');
1030         $data = array_reverse($data);
1031         reset($data);
1032         $count = 0;
1033         foreach($rs as $key => $record) {
1034             $data_record = current($data);
1035             $this->assertEqual($data_record['id'], $key);
1036             next($data);
1037             $count++;
1038         }
1039         $rs->close();
1040         $this->assertEqual($count, 3);
1041     }
1043     public function test_get_recordset_list() {
1044         $DB = $this->tdb;
1045         $dbman = $DB->get_manager();
1047         $table = $this->get_test_table();
1048         $tablename = $table->getName();
1050         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1051         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1052         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
1053         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1054         $dbman->create_table($table);
1056         $DB->insert_record($tablename, array('course' => 3));
1057         $DB->insert_record($tablename, array('course' => 3));
1058         $DB->insert_record($tablename, array('course' => 5));
1059         $DB->insert_record($tablename, array('course' => 2));
1061         $rs = $DB->get_recordset_list($tablename, 'course', array(3, 2));
1063         $counter = 0;
1064         foreach ($rs as $record) {
1065             $counter++;
1066         }
1067         $this->assertEqual(3, $counter);
1068         $rs->close();
1070         $rs = $DB->get_recordset_list($tablename, 'course',array()); /// Must return 0 rows without conditions. MDL-17645
1072         $counter = 0;
1073         foreach ($rs as $record) {
1074             $counter++;
1075         }
1076         $rs->close();
1077         $this->assertEqual(0, $counter);
1079         // notes:
1080         //  * limits are tested in test_get_recordset_sql()
1081         //  * where_clause() is used internally and is tested in test_get_records()
1082     }
1084     public function test_get_recordset_select() {
1085         $DB = $this->tdb;
1086         $dbman = $DB->get_manager();
1088         $table = $this->get_test_table();
1089         $tablename = $table->getName();
1091         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1092         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1093         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1094         $dbman->create_table($table);
1096         $DB->insert_record($tablename, array('course' => 3));
1097         $DB->insert_record($tablename, array('course' => 3));
1098         $DB->insert_record($tablename, array('course' => 5));
1099         $DB->insert_record($tablename, array('course' => 2));
1101         $rs = $DB->get_recordset_select($tablename, '');
1102         $counter = 0;
1103         foreach ($rs as $record) {
1104             $counter++;
1105         }
1106         $rs->close();
1107         $this->assertEqual(4, $counter);
1109         $this->assertTrue($rs = $DB->get_recordset_select($tablename, 'course = 3'));
1110         $counter = 0;
1111         foreach ($rs as $record) {
1112             $counter++;
1113         }
1114         $rs->close();
1115         $this->assertEqual(2, $counter);
1117         // notes:
1118         //  * limits are tested in test_get_recordset_sql()
1119     }
1121     public function test_get_recordset_sql() {
1122         $DB = $this->tdb;
1123         $dbman = $DB->get_manager();
1125         $table = $this->get_test_table();
1126         $tablename = $table->getName();
1128         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1129         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1130         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1131         $dbman->create_table($table);
1133         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
1134         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
1135         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
1136         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
1137         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
1138         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
1139         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
1141         $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
1142         $counter = 0;
1143         foreach ($rs as $record) {
1144             $counter++;
1145         }
1146         $rs->close();
1147         $this->assertEqual(2, $counter);
1149         // limits - only need to test this case, the rest have been tested by test_get_records_sql()
1150         // only limitfrom = skips that number of records
1151         $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
1152         $records = array();
1153         foreach($rs as $key => $record) {
1154             $records[$key] = $record;
1155         }
1156         $rs->close();
1157         $this->assertEqual(5, count($records));
1158         $this->assertEqual($inskey3, reset($records)->id);
1159         $this->assertEqual($inskey7, end($records)->id);
1161         // note: fetching nulls, empties, LOBs already tested by test_insert_record() no needed here
1162     }
1164     public function test_get_records() {
1165         $DB = $this->tdb;
1166         $dbman = $DB->get_manager();
1168         $table = $this->get_test_table();
1169         $tablename = $table->getName();
1171         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1172         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1173         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1174         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1175         $dbman->create_table($table);
1177         $DB->insert_record($tablename, array('course' => 3));
1178         $DB->insert_record($tablename, array('course' => 3));
1179         $DB->insert_record($tablename, array('course' => 5));
1180         $DB->insert_record($tablename, array('course' => 2));
1182         // All records
1183         $records = $DB->get_records($tablename);
1184         $this->assertEqual(4, count($records));
1185         $this->assertEqual(3, $records[1]->course);
1186         $this->assertEqual(3, $records[2]->course);
1187         $this->assertEqual(5, $records[3]->course);
1188         $this->assertEqual(2, $records[4]->course);
1190         // Records matching certain conditions
1191         $records = $DB->get_records($tablename, array('course' => 3));
1192         $this->assertEqual(2, count($records));
1193         $this->assertEqual(3, $records[1]->course);
1194         $this->assertEqual(3, $records[2]->course);
1196         // All records sorted by course
1197         $records = $DB->get_records($tablename, null, 'course');
1198         $this->assertEqual(4, count($records));
1199         $current_record = reset($records);
1200         $this->assertEqual(4, $current_record->id);
1201         $current_record = next($records);
1202         $this->assertEqual(1, $current_record->id);
1203         $current_record = next($records);
1204         $this->assertEqual(2, $current_record->id);
1205         $current_record = next($records);
1206         $this->assertEqual(3, $current_record->id);
1208         // All records, but get only one field
1209         $records = $DB->get_records($tablename, null, '', 'id');
1210         $this->assertFalse(isset($records[1]->course));
1211         $this->assertTrue(isset($records[1]->id));
1212         $this->assertEqual(4, count($records));
1214         // Booleans into params
1215         $records = $DB->get_records($tablename, array('course' => true));
1216         $this->assertEqual(0, count($records));
1217         $records = $DB->get_records($tablename, array('course' => false));
1218         $this->assertEqual(0, count($records));
1220         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
1221         $conditions = array('onetext' => '1');
1222         try {
1223             $records = $DB->get_records($tablename, $conditions);
1224             $this->fail('An Exception is missing, expected due to equating of text fields');
1225         } catch (exception $e) {
1226             $this->assertTrue($e instanceof dml_exception);
1227             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
1228         }
1230         // note: delegate limits testing to test_get_records_sql()
1231     }
1233     public function test_get_records_list() {
1234         $DB = $this->tdb;
1235         $dbman = $DB->get_manager();
1237         $table = $this->get_test_table();
1238         $tablename = $table->getName();
1240         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1241         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1242         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1243         $dbman->create_table($table);
1245         $DB->insert_record($tablename, array('course' => 3));
1246         $DB->insert_record($tablename, array('course' => 3));
1247         $DB->insert_record($tablename, array('course' => 5));
1248         $DB->insert_record($tablename, array('course' => 2));
1250         $records = $DB->get_records_list($tablename, 'course', array(3, 2));
1251         $this->assertTrue(is_array($records));
1252         $this->assertEqual(3, count($records));
1253         $this->assertEqual(1, reset($records)->id);
1254         $this->assertEqual(2, next($records)->id);
1255         $this->assertEqual(4, next($records)->id);
1257         $this->assertIdentical(array(), $records = $DB->get_records_list($tablename, 'course', array())); /// Must return 0 rows without conditions. MDL-17645
1258         $this->assertEqual(0, count($records));
1260         // note: delegate limits testing to test_get_records_sql()
1261     }
1263     public function test_get_records_sql() {
1264         $DB = $this->tdb;
1265         $dbman = $DB->get_manager();
1267         $table = $this->get_test_table();
1268         $tablename = $table->getName();
1270         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1271         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1272         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1273         $dbman->create_table($table);
1275         $inskey1 = $DB->insert_record($tablename, array('course' => 3));
1276         $inskey2 = $DB->insert_record($tablename, array('course' => 5));
1277         $inskey3 = $DB->insert_record($tablename, array('course' => 4));
1278         $inskey4 = $DB->insert_record($tablename, array('course' => 3));
1279         $inskey5 = $DB->insert_record($tablename, array('course' => 2));
1280         $inskey6 = $DB->insert_record($tablename, array('course' => 1));
1281         $inskey7 = $DB->insert_record($tablename, array('course' => 0));
1283         $table2 = $this->get_test_table("2");
1284         $tablename2 = $table2->getName();
1285         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1286         $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1287         $table2->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
1288         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1289         $dbman->create_table($table2);
1291         $DB->insert_record($tablename2, array('course'=>3, 'nametext'=>'badabing'));
1292         $DB->insert_record($tablename2, array('course'=>4, 'nametext'=>'badabang'));
1293         $DB->insert_record($tablename2, array('course'=>5, 'nametext'=>'badabung'));
1294         $DB->insert_record($tablename2, array('course'=>6, 'nametext'=>'badabong'));
1296         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
1297         $this->assertEqual(2, count($records));
1298         $this->assertEqual($inskey1, reset($records)->id);
1299         $this->assertEqual($inskey4, next($records)->id);
1301         // Awful test, requires debug enabled and sent to browser. Let's do that and restore after test
1302         $this->enable_debugging();
1303         $records = $DB->get_records_sql("SELECT course AS id, course AS course FROM {{$tablename}}", null);
1304         $this->assertFalse($this->get_debugging() === '');
1305         $this->assertEqual(6, count($records));
1307         // negative limits = no limits
1308         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, -1, -1);
1309         $this->assertEqual(7, count($records));
1311         // zero limits = no limits
1312         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 0);
1313         $this->assertEqual(7, count($records));
1315         // only limitfrom = skips that number of records
1316         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
1317         $this->assertEqual(5, count($records));
1318         $this->assertEqual($inskey3, reset($records)->id);
1319         $this->assertEqual($inskey7, end($records)->id);
1321         // only limitnum = fetches that number of records
1322         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 3);
1323         $this->assertEqual(3, count($records));
1324         $this->assertEqual($inskey1, reset($records)->id);
1325         $this->assertEqual($inskey3, end($records)->id);
1327         // both limitfrom and limitnum = skips limitfrom records and fetches limitnum ones
1328         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 3, 2);
1329         $this->assertEqual(2, count($records));
1330         $this->assertEqual($inskey4, reset($records)->id);
1331         $this->assertEqual($inskey5, end($records)->id);
1333         // both limitfrom and limitnum in query having subqueris
1334         // note the subquery skips records with course = 0 and 3
1335         $sql = "SELECT * FROM {{$tablename}}
1336                  WHERE course NOT IN (
1337                      SELECT course FROM {{$tablename}}
1338                       WHERE course IN (0, 3))
1339                 ORDER BY course";
1340         $records = $DB->get_records_sql($sql, null, 0, 2); // Skip 0, get 2
1341         $this->assertEqual(2, count($records));
1342         $this->assertEqual($inskey6, reset($records)->id);
1343         $this->assertEqual($inskey5, end($records)->id);
1344         $records = $DB->get_records_sql($sql, null, 2, 2); // Skip 2, get 2
1345         $this->assertEqual(2, count($records));
1346         $this->assertEqual($inskey3, reset($records)->id);
1347         $this->assertEqual($inskey2, end($records)->id);
1349         // test 2 tables with aliases and limits with order bys
1350         $sql = "SELECT t1.id, t1.course AS cid, t2.nametext
1351                   FROM {{$tablename}} t1, {{$tablename2}} t2
1352                  WHERE t2.course=t1.course
1353               ORDER BY t1.course, ". $DB->sql_compare_text('t2.nametext');
1354         $records = $DB->get_records_sql($sql, null, 2, 2); // Skip courses 3 and 6, get 4 and 5
1355         $this->assertEqual(2, count($records));
1356         $this->assertEqual('5', end($records)->cid);
1357         $this->assertEqual('4', reset($records)->cid);
1359         // test 2 tables with aliases and limits with the highest INT limit works
1360         $records = $DB->get_records_sql($sql, null, 2, PHP_INT_MAX); // Skip course {3,6}, get {4,5}
1361         $this->assertEqual(2, count($records));
1362         $this->assertEqual('5', end($records)->cid);
1363         $this->assertEqual('4', reset($records)->cid);
1365         // test 2 tables with aliases and limits with order bys (limit which is highest INT number)
1366         $records = $DB->get_records_sql($sql, null, PHP_INT_MAX, 2); // Skip all courses
1367         $this->assertEqual(0, count($records));
1369         // test 2 tables with aliases and limits with order bys (limit which s highest INT number)
1370         $records = $DB->get_records_sql($sql, null, PHP_INT_MAX, PHP_INT_MAX); // Skip all courses
1371         $this->assertEqual(0, count($records));
1373         // TODO: Test limits in queries having DISTINCT clauses
1375         // note: fetching nulls, empties, LOBs already tested by test_update_record() no needed here
1376     }
1378     public function test_get_records_menu() {
1379         $DB = $this->tdb;
1380         $dbman = $DB->get_manager();
1382         $table = $this->get_test_table();
1383         $tablename = $table->getName();
1385         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1386         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1387         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1388         $dbman->create_table($table);
1390         $DB->insert_record($tablename, array('course' => 3));
1391         $DB->insert_record($tablename, array('course' => 3));
1392         $DB->insert_record($tablename, array('course' => 5));
1393         $DB->insert_record($tablename, array('course' => 2));
1395         $records = $DB->get_records_menu($tablename, array('course' => 3));
1396         $this->assertTrue(is_array($records));
1397         $this->assertEqual(2, count($records));
1398         $this->assertFalse(empty($records[1]));
1399         $this->assertFalse(empty($records[2]));
1400         $this->assertEqual(3, $records[1]);
1401         $this->assertEqual(3, $records[2]);
1403         // note: delegate limits testing to test_get_records_sql()
1404     }
1406     public function test_get_records_select_menu() {
1407         $DB = $this->tdb;
1408         $dbman = $DB->get_manager();
1410         $table = $this->get_test_table();
1411         $tablename = $table->getName();
1413         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1414         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1415         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1416         $dbman->create_table($table);
1418         $DB->insert_record($tablename, array('course' => 3));
1419         $DB->insert_record($tablename, array('course' => 2));
1420         $DB->insert_record($tablename, array('course' => 3));
1421         $DB->insert_record($tablename, array('course' => 5));
1423         $records = $DB->get_records_select_menu($tablename, "course > ?", array(2));
1424         $this->assertTrue(is_array($records));
1426         $this->assertEqual(3, count($records));
1427         $this->assertFalse(empty($records[1]));
1428         $this->assertTrue(empty($records[2]));
1429         $this->assertFalse(empty($records[3]));
1430         $this->assertFalse(empty($records[4]));
1431         $this->assertEqual(3, $records[1]);
1432         $this->assertEqual(3, $records[3]);
1433         $this->assertEqual(5, $records[4]);
1435         // note: delegate limits testing to test_get_records_sql()
1436     }
1438     public function test_get_records_sql_menu() {
1439         $DB = $this->tdb;
1440         $dbman = $DB->get_manager();
1442         $table = $this->get_test_table();
1443         $tablename = $table->getName();
1445         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1446         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1447         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1448         $dbman->create_table($table);
1450         $DB->insert_record($tablename, array('course' => 3));
1451         $DB->insert_record($tablename, array('course' => 2));
1452         $DB->insert_record($tablename, array('course' => 3));
1453         $DB->insert_record($tablename, array('course' => 5));
1455         $records = $DB->get_records_sql_menu("SELECT * FROM {{$tablename}} WHERE course > ?", array(2));
1456         $this->assertTrue(is_array($records));
1458         $this->assertEqual(3, count($records));
1459         $this->assertFalse(empty($records[1]));
1460         $this->assertTrue(empty($records[2]));
1461         $this->assertFalse(empty($records[3]));
1462         $this->assertFalse(empty($records[4]));
1463         $this->assertEqual(3, $records[1]);
1464         $this->assertEqual(3, $records[3]);
1465         $this->assertEqual(5, $records[4]);
1467         // note: delegate limits testing to test_get_records_sql()
1468     }
1470     public function test_get_record() {
1471         $DB = $this->tdb;
1472         $dbman = $DB->get_manager();
1474         $table = $this->get_test_table();
1475         $tablename = $table->getName();
1477         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1478         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1479         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1480         $dbman->create_table($table);
1482         $DB->insert_record($tablename, array('course' => 3));
1483         $DB->insert_record($tablename, array('course' => 2));
1485         $record = $DB->get_record($tablename, array('id' => 2));
1486         $this->assertTrue($record instanceof stdClass);
1488         $this->assertEqual(2, $record->course);
1489         $this->assertEqual(2, $record->id);
1490     }
1493     public function test_get_record_select() {
1494         $DB = $this->tdb;
1495         $dbman = $DB->get_manager();
1497         $table = $this->get_test_table();
1498         $tablename = $table->getName();
1500         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1501         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1502         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1503         $dbman->create_table($table);
1505         $DB->insert_record($tablename, array('course' => 3));
1506         $DB->insert_record($tablename, array('course' => 2));
1508         $record = $DB->get_record_select($tablename, "id = ?", array(2));
1509         $this->assertTrue($record instanceof stdClass);
1511         $this->assertEqual(2, $record->course);
1513         // note: delegates limit testing to test_get_records_sql()
1514     }
1516     public function test_get_record_sql() {
1517         $DB = $this->tdb;
1518         $dbman = $DB->get_manager();
1520         $table = $this->get_test_table();
1521         $tablename = $table->getName();
1523         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1524         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1525         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1526         $dbman->create_table($table);
1528         $DB->insert_record($tablename, array('course' => 3));
1529         $DB->insert_record($tablename, array('course' => 2));
1531         // standard use
1532         $record = $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(2));
1533         $this->assertTrue($record instanceof stdClass);
1534         $this->assertEqual(2, $record->course);
1535         $this->assertEqual(2, $record->id);
1537         // backwards compatibility with $ignoremultiple
1538         $this->assertFalse(IGNORE_MISSING);
1539         $this->assertTrue(IGNORE_MULTIPLE);
1541         // record not found - ignore
1542         $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MISSING));
1543         $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MULTIPLE));
1545         // record not found error
1546         try {
1547             $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), MUST_EXIST);
1548             $this->fail("Exception expected");
1549         } catch (dml_missing_record_exception $e) {
1550             $this->assertTrue(true);
1551         }
1553         $this->enable_debugging();
1554         $this->assertTrue($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MISSING));
1555         $this->assertFalse($this->get_debugging() === '');
1557         // multiple matches ignored
1558         $this->assertTrue($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MULTIPLE));
1560         // multiple found error
1561         try {
1562             $DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), MUST_EXIST);
1563             $this->fail("Exception expected");
1564         } catch (dml_multiple_records_exception $e) {
1565             $this->assertTrue(true);
1566         }
1567     }
1569     public function test_get_field() {
1570         $DB = $this->tdb;
1571         $dbman = $DB->get_manager();
1573         $table = $this->get_test_table();
1574         $tablename = $table->getName();
1576         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1577         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1578         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1579         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1580         $dbman->create_table($table);
1582         $id1 = $DB->insert_record($tablename, array('course' => 3));
1583         $DB->insert_record($tablename, array('course' => 5));
1584         $DB->insert_record($tablename, array('course' => 5));
1586         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id1)));
1587         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('course' => 3)));
1589         $this->assertIdentical(false, $DB->get_field($tablename, 'course', array('course' => 11), IGNORE_MISSING));
1590         try {
1591             $DB->get_field($tablename, 'course', array('course' => 4), MUST_EXIST);
1592             $this->assertFail('Exception expected due to missing record');
1593         } catch (dml_exception $ex) {
1594             $this->assertTrue(true);
1595         }
1597         $this->enable_debugging();
1598         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MULTIPLE));
1599         $this->assertIdentical($this->get_debugging(), '');
1601         $this->enable_debugging();
1602         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MISSING));
1603         $this->assertFalse($this->get_debugging() === '');
1605         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
1606         $conditions = array('onetext' => '1');
1607         try {
1608             $DB->get_field($tablename, 'course', $conditions);
1609             $this->fail('An Exception is missing, expected due to equating of text fields');
1610         } catch (exception $e) {
1611             $this->assertTrue($e instanceof dml_exception);
1612             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
1613         }
1614     }
1616     public function test_get_field_select() {
1617         $DB = $this->tdb;
1618         $dbman = $DB->get_manager();
1620         $table = $this->get_test_table();
1621         $tablename = $table->getName();
1623         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1624         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1625         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1626         $dbman->create_table($table);
1628         $DB->insert_record($tablename, array('course' => 3));
1630         $this->assertEqual(3, $DB->get_field_select($tablename, 'course', "id = ?", array(1)));
1631     }
1633     public function test_get_field_sql() {
1634         $DB = $this->tdb;
1635         $dbman = $DB->get_manager();
1637         $table = $this->get_test_table();
1638         $tablename = $table->getName();
1640         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1641         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1642         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1643         $dbman->create_table($table);
1645         $DB->insert_record($tablename, array('course' => 3));
1647         $this->assertEqual(3, $DB->get_field_sql("SELECT course FROM {{$tablename}} WHERE id = ?", array(1)));
1648     }
1650     public function test_get_fieldset_select() {
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_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1660         $dbman->create_table($table);
1662         $DB->insert_record($tablename, array('course' => 1));
1663         $DB->insert_record($tablename, array('course' => 3));
1664         $DB->insert_record($tablename, array('course' => 2));
1665         $DB->insert_record($tablename, array('course' => 6));
1667         $fieldset = $DB->get_fieldset_select($tablename, 'course', "course > ?", array(1));
1668         $this->assertTrue(is_array($fieldset));
1670         $this->assertEqual(3, count($fieldset));
1671         $this->assertEqual(3, $fieldset[0]);
1672         $this->assertEqual(2, $fieldset[1]);
1673         $this->assertEqual(6, $fieldset[2]);
1674     }
1676     public function test_get_fieldset_sql() {
1677         $DB = $this->tdb;
1678         $dbman = $DB->get_manager();
1680         $table = $this->get_test_table();
1681         $tablename = $table->getName();
1683         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1684         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1685         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1686         $dbman->create_table($table);
1688         $DB->insert_record($tablename, array('course' => 1));
1689         $DB->insert_record($tablename, array('course' => 3));
1690         $DB->insert_record($tablename, array('course' => 2));
1691         $DB->insert_record($tablename, array('course' => 6));
1693         $fieldset = $DB->get_fieldset_sql("SELECT * FROM {{$tablename}} WHERE course > ?", array(1));
1694         $this->assertTrue(is_array($fieldset));
1696         $this->assertEqual(3, count($fieldset));
1697         $this->assertEqual(2, $fieldset[0]);
1698         $this->assertEqual(3, $fieldset[1]);
1699         $this->assertEqual(4, $fieldset[2]);
1700     }
1702     public function test_insert_record_raw() {
1703         $DB = $this->tdb;
1704         $dbman = $DB->get_manager();
1706         $table = $this->get_test_table();
1707         $tablename = $table->getName();
1709         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1710         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1711         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1712         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1713         $dbman->create_table($table);
1715         $record = (object)array('course' => 1, 'onechar' => 'xx');
1716         $before = clone($record);
1717         $result = $DB->insert_record_raw($tablename, $record);
1718         $this->assertIdentical(1, $result);
1719         $this->assertIdentical($record, $before);
1721         $record = $DB->get_record($tablename, array('course' => 1));
1722         $this->assertTrue($record instanceof stdClass);
1723         $this->assertIdentical('xx', $record->onechar);
1725         $result = $DB->insert_record_raw($tablename, array('course' => 2, 'onechar' => 'yy'), false);
1726         $this->assertIdentical(true, $result);
1728         // note: bulk not implemented yet
1729         $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'zz'), true, true);
1730         $record = $DB->get_record($tablename, array('course' => 3));
1731         $this->assertTrue($record instanceof stdClass);
1732         $this->assertIdentical('zz', $record->onechar);
1734         // custom sequence (id) - returnid is ignored
1735         $result = $DB->insert_record_raw($tablename, array('id' => 10, 'course' => 3, 'onechar' => 'bb'), true, false, true);
1736         $this->assertIdentical(true, $result);
1737         $record = $DB->get_record($tablename, array('id' => 10));
1738         $this->assertTrue($record instanceof stdClass);
1739         $this->assertIdentical('bb', $record->onechar);
1741         // custom sequence - missing id error
1742         try {
1743             $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'bb'), true, false, true);
1744             $this->assertFail('Exception expected due to missing record');
1745         } catch (coding_exception $ex) {
1746             $this->assertTrue(true);
1747         }
1749         // wrong column error
1750         try {
1751             $DB->insert_record_raw($tablename, array('xxxxx' => 3, 'onechar' => 'bb'));
1752             $this->assertFail('Exception expected due to invalid column');
1753         } catch (dml_write_exception $ex) {
1754             $this->assertTrue(true);
1755         }
1756     }
1758     public function test_insert_record() {
1759         // All the information in this test is fetched from DB by get_recordset() so we
1760         // have such method properly tested against nulls, empties and friends...
1762         $DB = $this->tdb;
1763         $dbman = $DB->get_manager();
1765         $table = $this->get_test_table();
1766         $tablename = $table->getName();
1768         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1769         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
1770         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
1771         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1772         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1773         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1774         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
1775         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1776         $dbman->create_table($table);
1778         $this->assertIdentical(1, $DB->insert_record($tablename, array('course' => 1), true));
1779         $record = $DB->get_record($tablename, array('course' => 1));
1780         $this->assertEqual(1, $record->id);
1781         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
1782         $this->assertEqual(200, $record->onenum);
1783         $this->assertIdentical('onestring', $record->onechar);
1784         $this->assertNull($record->onetext);
1785         $this->assertNull($record->onebinary);
1787         // without returning id, bulk not implemented
1788         $result = $this->assertIdentical(true, $DB->insert_record($tablename, array('course' => 99), false, true));
1789         $record = $DB->get_record($tablename, array('course' => 99));
1790         $this->assertEqual(2, $record->id);
1791         $this->assertEqual(99, $record->course);
1793         // Check nulls are set properly for all types
1794         $record = new stdClass();
1795         $record->oneint = null;
1796         $record->onenum = null;
1797         $record->onechar = null;
1798         $record->onetext = null;
1799         $record->onebinary = null;
1800         $recid = $DB->insert_record($tablename, $record);
1801         $record = $DB->get_record($tablename, array('id' => $recid));
1802         $this->assertEqual(0, $record->course);
1803         $this->assertNull($record->oneint);
1804         $this->assertNull($record->onenum);
1805         $this->assertNull($record->onechar);
1806         $this->assertNull($record->onetext);
1807         $this->assertNull($record->onebinary);
1809         // Check zeros are set properly for all types
1810         $record = new stdClass();
1811         $record->oneint = 0;
1812         $record->onenum = 0;
1813         $recid = $DB->insert_record($tablename, $record);
1814         $record = $DB->get_record($tablename, array('id' => $recid));
1815         $this->assertEqual(0, $record->oneint);
1816         $this->assertEqual(0, $record->onenum);
1818         // Check booleans are set properly for all types
1819         $record = new stdClass();
1820         $record->oneint = true; // trues
1821         $record->onenum = true;
1822         $record->onechar = true;
1823         $record->onetext = true;
1824         $recid = $DB->insert_record($tablename, $record);
1825         $record = $DB->get_record($tablename, array('id' => $recid));
1826         $this->assertEqual(1, $record->oneint);
1827         $this->assertEqual(1, $record->onenum);
1828         $this->assertEqual(1, $record->onechar);
1829         $this->assertEqual(1, $record->onetext);
1831         $record = new stdClass();
1832         $record->oneint = false; // falses
1833         $record->onenum = false;
1834         $record->onechar = false;
1835         $record->onetext = false;
1836         $recid = $DB->insert_record($tablename, $record);
1837         $record = $DB->get_record($tablename, array('id' => $recid));
1838         $this->assertEqual(0, $record->oneint);
1839         $this->assertEqual(0, $record->onenum);
1840         $this->assertEqual(0, $record->onechar);
1841         $this->assertEqual(0, $record->onetext);
1843         // Check string data causes exception in numeric types
1844         $record = new stdClass();
1845         $record->oneint = 'onestring';
1846         $record->onenum = 0;
1847         try {
1848             $DB->insert_record($tablename, $record);
1849             $this->fail("Expecting an exception, none occurred");
1850         } catch (exception $e) {
1851             $this->assertTrue($e instanceof dml_exception);
1852         }
1853         $record = new stdClass();
1854         $record->oneint = 0;
1855         $record->onenum = 'onestring';
1856         try {
1857            $DB->insert_record($tablename, $record);
1858            $this->fail("Expecting an exception, none occurred");
1859         } catch (exception $e) {
1860             $this->assertTrue($e instanceof dml_exception);
1861         }
1863         // Check empty string data is stored as 0 in numeric datatypes
1864         $record = new stdClass();
1865         $record->oneint = ''; // empty string
1866         $record->onenum = 0;
1867         $recid = $DB->insert_record($tablename, $record);
1868         $record = $DB->get_record($tablename, array('id' => $recid));
1869         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
1871         $record = new stdClass();
1872         $record->oneint = 0;
1873         $record->onenum = ''; // empty string
1874         $recid = $DB->insert_record($tablename, $record);
1875         $record = $DB->get_record($tablename, array('id' => $recid));
1876         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
1878         // Check empty strings are set properly in string types
1879         $record = new stdClass();
1880         $record->oneint = 0;
1881         $record->onenum = 0;
1882         $record->onechar = '';
1883         $record->onetext = '';
1884         $recid = $DB->insert_record($tablename, $record);
1885         $record = $DB->get_record($tablename, array('id' => $recid));
1886         $this->assertTrue($record->onechar === '');
1887         $this->assertTrue($record->onetext === '');
1889         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
1890         $record = new stdClass();
1891         $record->oneint = ((210.10 + 39.92) - 150.02);
1892         $record->onenum = ((210.10 + 39.92) - 150.02);
1893         $recid = $DB->insert_record($tablename, $record);
1894         $record = $DB->get_record($tablename, array('id' => $recid));
1895         $this->assertEqual(100, $record->oneint);
1896         $this->assertEqual(100, $record->onenum);
1898         // Check various quotes/backslashes combinations in string types
1899         $teststrings = array(
1900             'backslashes and quotes alone (even): "" \'\' \\\\',
1901             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
1902             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
1903             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
1904         foreach ($teststrings as $teststring) {
1905             $record = new stdClass();
1906             $record->onechar = $teststring;
1907             $record->onetext = $teststring;
1908             $recid = $DB->insert_record($tablename, $record);
1909             $record = $DB->get_record($tablename, array('id' => $recid));
1910             $this->assertEqual($teststring, $record->onechar);
1911             $this->assertEqual($teststring, $record->onetext);
1912         }
1914         // Check LOBs in text/binary columns
1915         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
1916         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
1917         $record = new stdClass();
1918         $record->onetext = $clob;
1919         $record->onebinary = $blob;
1920         $recid = $DB->insert_record($tablename, $record);
1921         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1922         $record = $rs->current();
1923         $rs->close();
1924         $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
1925         $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
1927         // And "small" LOBs too, just in case
1928         $newclob = substr($clob, 0, 500);
1929         $newblob = substr($blob, 0, 250);
1930         $record = new stdClass();
1931         $record->onetext = $newclob;
1932         $record->onebinary = $newblob;
1933         $recid = $DB->insert_record($tablename, $record);
1934         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1935         $record = $rs->current();
1936         $rs->close();
1937         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
1938         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
1939         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
1941         // And "diagnostic" LOBs too, just in case
1942         $newclob = '\'"\\;/ěščřžýáíé';
1943         $newblob = '\'"\\;/ěščřžýáíé';
1944         $record = new stdClass();
1945         $record->onetext = $newclob;
1946         $record->onebinary = $newblob;
1947         $recid = $DB->insert_record($tablename, $record);
1948         $rs = $DB->get_recordset($tablename, array('id' => $recid));
1949         $record = $rs->current();
1950         $rs->close();
1951         $this->assertIdentical($newclob, $record->onetext);
1952         $this->assertIdentical($newblob, $record->onebinary);
1953         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
1955         // test data is not modified
1956         $record = new stdClass();
1957         $record->id     = -1; // has to be ignored
1958         $record->course = 3;
1959         $record->lalala = 'lalal'; // unused
1960         $before = clone($record);
1961         $DB->insert_record($tablename, $record);
1962         $this->assertEqual($record, $before);
1964         // make sure the id is always increasing and never reuses the same id
1965         $id1 = $DB->insert_record($tablename, array('course' => 3));
1966         $id2 = $DB->insert_record($tablename, array('course' => 3));
1967         $this->assertTrue($id1 < $id2);
1968         $DB->delete_records($tablename, array('id'=>$id2));
1969         $id3 = $DB->insert_record($tablename, array('course' => 3));
1970         $this->assertTrue($id2 < $id3);
1971         $DB->delete_records($tablename, array());
1972         $id4 = $DB->insert_record($tablename, array('course' => 3));
1973         $this->assertTrue($id3 < $id4);
1975         // Test saving a float in a CHAR column, and reading it back.
1976         $id = $DB->insert_record($tablename, array('onechar' => 1.0));
1977         $this->assertEqual(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
1978         $id = $DB->insert_record($tablename, array('onechar' => 1e20));
1979         $this->assertEqual(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
1980         $id = $DB->insert_record($tablename, array('onechar' => 1e-4));
1981         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
1982         $id = $DB->insert_record($tablename, array('onechar' => 1e-5));
1983         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
1984         $id = $DB->insert_record($tablename, array('onechar' => 1e-300));
1985         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
1986         $id = $DB->insert_record($tablename, array('onechar' => 1e300));
1987         $this->assertEqual(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
1989         // Test saving a float in a TEXT column, and reading it back.
1990         $id = $DB->insert_record($tablename, array('onetext' => 1.0));
1991         $this->assertEqual(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
1992         $id = $DB->insert_record($tablename, array('onetext' => 1e20));
1993         $this->assertEqual(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
1994         $id = $DB->insert_record($tablename, array('onetext' => 1e-4));
1995         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
1996         $id = $DB->insert_record($tablename, array('onetext' => 1e-5));
1997         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
1998         $id = $DB->insert_record($tablename, array('onetext' => 1e-300));
1999         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2000         $id = $DB->insert_record($tablename, array('onetext' => 1e300));
2001         $this->assertEqual(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2002     }
2004     public function test_import_record() {
2005         // All the information in this test is fetched from DB by get_recordset() so we
2006         // have such method properly tested against nulls, empties and friends...
2008         $DB = $this->tdb;
2009         $dbman = $DB->get_manager();
2011         $table = $this->get_test_table();
2012         $tablename = $table->getName();
2014         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2015         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2016         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
2017         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
2018         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
2019         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2020         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2021         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2022         $dbman->create_table($table);
2024         $this->assertIdentical(1, $DB->insert_record($tablename, array('course' => 1), true));
2025         $record = $DB->get_record($tablename, array('course' => 1));
2026         $this->assertEqual(1, $record->id);
2027         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
2028         $this->assertEqual(200, $record->onenum);
2029         $this->assertIdentical('onestring', $record->onechar);
2030         $this->assertNull($record->onetext);
2031         $this->assertNull($record->onebinary);
2033         // ignore extra columns
2034         $record = (object)array('id'=>13, 'course'=>2, 'xxxx'=>788778);
2035         $before = clone($record);
2036         $this->assertIdentical(true, $DB->import_record($tablename, $record));
2037         $this->assertIdentical($record, $before);
2038         $records = $DB->get_records($tablename);
2039         $this->assertEqual(2, $records[13]->course);
2041         // Check nulls are set properly for all types
2042         $record = new stdClass();
2043         $record->id = 20;
2044         $record->oneint = null;
2045         $record->onenum = null;
2046         $record->onechar = null;
2047         $record->onetext = null;
2048         $record->onebinary = null;
2049         $this->assertTrue($DB->import_record($tablename, $record));
2050         $record = $DB->get_record($tablename, array('id' => 20));
2051         $this->assertEqual(0, $record->course);
2052         $this->assertNull($record->oneint);
2053         $this->assertNull($record->onenum);
2054         $this->assertNull($record->onechar);
2055         $this->assertNull($record->onetext);
2056         $this->assertNull($record->onebinary);
2058         // Check zeros are set properly for all types
2059         $record = new stdClass();
2060         $record->id = 23;
2061         $record->oneint = 0;
2062         $record->onenum = 0;
2063         $this->assertTrue($DB->import_record($tablename, $record));
2064         $record = $DB->get_record($tablename, array('id' => 23));
2065         $this->assertEqual(0, $record->oneint);
2066         $this->assertEqual(0, $record->onenum);
2068         // Check string data causes exception in numeric types
2069         $record = new stdClass();
2070         $record->id = 32;
2071         $record->oneint = 'onestring';
2072         $record->onenum = 0;
2073         try {
2074             $DB->import_record($tablename, $record);
2075             $this->fail("Expecting an exception, none occurred");
2076         } catch (exception $e) {
2077             $this->assertTrue($e instanceof dml_exception);
2078         }
2079         $record = new stdClass();
2080         $record->id = 35;
2081         $record->oneint = 0;
2082         $record->onenum = 'onestring';
2083         try {
2084            $DB->import_record($tablename, $record);
2085            $this->fail("Expecting an exception, none occurred");
2086         } catch (exception $e) {
2087             $this->assertTrue($e instanceof dml_exception);
2088         }
2090         // Check empty strings are set properly in string types
2091         $record = new stdClass();
2092         $record->id = 44;
2093         $record->oneint = 0;
2094         $record->onenum = 0;
2095         $record->onechar = '';
2096         $record->onetext = '';
2097         $this->assertTrue($DB->import_record($tablename, $record));
2098         $record = $DB->get_record($tablename, array('id' => 44));
2099         $this->assertTrue($record->onechar === '');
2100         $this->assertTrue($record->onetext === '');
2102         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
2103         $record = new stdClass();
2104         $record->id = 47;
2105         $record->oneint = ((210.10 + 39.92) - 150.02);
2106         $record->onenum = ((210.10 + 39.92) - 150.02);
2107         $this->assertTrue($DB->import_record($tablename, $record));
2108         $record = $DB->get_record($tablename, array('id' => 47));
2109         $this->assertEqual(100, $record->oneint);
2110         $this->assertEqual(100, $record->onenum);
2112         // Check various quotes/backslashes combinations in string types
2113         $i = 50;
2114         $teststrings = array(
2115             'backslashes and quotes alone (even): "" \'\' \\\\',
2116             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2117             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2118             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2119         foreach ($teststrings as $teststring) {
2120             $record = new stdClass();
2121             $record->id = $i;
2122             $record->onechar = $teststring;
2123             $record->onetext = $teststring;
2124             $this->assertTrue($DB->import_record($tablename, $record));
2125             $record = $DB->get_record($tablename, array('id' => $i));
2126             $this->assertEqual($teststring, $record->onechar);
2127             $this->assertEqual($teststring, $record->onetext);
2128             $i = $i + 3;
2129         }
2131         // Check LOBs in text/binary columns
2132         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
2133         $record = new stdClass();
2134         $record->id = 70;
2135         $record->onetext = $clob;
2136         $record->onebinary = '';
2137         $this->assertTrue($DB->import_record($tablename, $record));
2138         $rs = $DB->get_recordset($tablename, array('id' => 70));
2139         $record = $rs->current();
2140         $rs->close();
2141         $this->assertEqual($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
2143         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
2144         $record = new stdClass();
2145         $record->id = 71;
2146         $record->onetext = '';
2147         $record->onebinary = $blob;
2148         $this->assertTrue($DB->import_record($tablename, $record));
2149         $rs = $DB->get_recordset($tablename, array('id' => 71));
2150         $record = $rs->current();
2151         $rs->close();
2152         $this->assertEqual($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
2154         // And "small" LOBs too, just in case
2155         $newclob = substr($clob, 0, 500);
2156         $newblob = substr($blob, 0, 250);
2157         $record = new stdClass();
2158         $record->id = 73;
2159         $record->onetext = $newclob;
2160         $record->onebinary = $newblob;
2161         $this->assertTrue($DB->import_record($tablename, $record));
2162         $rs = $DB->get_recordset($tablename, array('id' => 73));
2163         $record = $rs->current();
2164         $rs->close();
2165         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
2166         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
2167         $this->assertEqual(false, $rs->key()); // Ensure recordset key() method to be working ok after closing
2168     }
2170     public function test_update_record_raw() {
2171         $DB = $this->tdb;
2172         $dbman = $DB->get_manager();
2174         $table = $this->get_test_table();
2175         $tablename = $table->getName();
2177         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2178         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2179         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2180         $dbman->create_table($table);
2182         $DB->insert_record($tablename, array('course' => 1));
2183         $DB->insert_record($tablename, array('course' => 3));
2185         $record = $DB->get_record($tablename, array('course' => 1));
2186         $record->course = 2;
2187         $this->assertTrue($DB->update_record_raw($tablename, $record));
2188         $this->assertEqual(0, $DB->count_records($tablename, array('course' => 1)));
2189         $this->assertEqual(1, $DB->count_records($tablename, array('course' => 2)));
2190         $this->assertEqual(1, $DB->count_records($tablename, array('course' => 3)));
2192         $record = $DB->get_record($tablename, array('course' => 1));
2193         $record->xxxxx = 2;
2194         try {
2195            $DB->update_record_raw($tablename, $record);
2196            $this->fail("Expecting an exception, none occurred");
2197         } catch (Exception $e) {
2198             $this->assertTrue($e instanceof coding_exception);
2199         }
2201         $record = $DB->get_record($tablename, array('course' => 3));
2202         unset($record->id);
2203         try {
2204            $DB->update_record_raw($tablename, $record);
2205            $this->fail("Expecting an exception, none occurred");
2206         } catch (Exception $e) {
2207             $this->assertTrue($e instanceof coding_exception);
2208         }
2209     }
2211     public function test_update_record() {
2213         // All the information in this test is fetched from DB by get_record() so we
2214         // have such method properly tested against nulls, empties and friends...
2216         $DB = $this->tdb;
2217         $dbman = $DB->get_manager();
2219         $table = $this->get_test_table();
2220         $tablename = $table->getName();
2222         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2223         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2224         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, 100);
2225         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
2226         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
2227         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2228         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2229         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2230         $dbman->create_table($table);
2232         $DB->insert_record($tablename, array('course' => 1));
2233         $record = $DB->get_record($tablename, array('course' => 1));
2234         $record->course = 2;
2236         $this->assertTrue($DB->update_record($tablename, $record));
2237         $this->assertFalse($record = $DB->get_record($tablename, array('course' => 1)));
2238         $this->assertTrue($record = $DB->get_record($tablename, array('course' => 2)));
2239         $this->assertEqual(100, $record->oneint); // Just check column defaults have been applied
2240         $this->assertEqual(200, $record->onenum);
2241         $this->assertEqual('onestring', $record->onechar);
2242         $this->assertNull($record->onetext);
2243         $this->assertNull($record->onebinary);
2245         // Check nulls are set properly for all types
2246         $record->oneint = null;
2247         $record->onenum = null;
2248         $record->onechar = null;
2249         $record->onetext = null;
2250         $record->onebinary = null;
2251         $DB->update_record($tablename, $record);
2252         $record = $DB->get_record($tablename, array('course' => 2));
2253         $this->assertNull($record->oneint);
2254         $this->assertNull($record->onenum);
2255         $this->assertNull($record->onechar);
2256         $this->assertNull($record->onetext);
2257         $this->assertNull($record->onebinary);
2259         // Check zeros are set properly for all types
2260         $record->oneint = 0;
2261         $record->onenum = 0;
2262         $DB->update_record($tablename, $record);
2263         $record = $DB->get_record($tablename, array('course' => 2));
2264         $this->assertEqual(0, $record->oneint);
2265         $this->assertEqual(0, $record->onenum);
2267         // Check booleans are set properly for all types
2268         $record->oneint = true; // trues
2269         $record->onenum = true;
2270         $record->onechar = true;
2271         $record->onetext = true;
2272         $DB->update_record($tablename, $record);
2273         $record = $DB->get_record($tablename, array('course' => 2));
2274         $this->assertEqual(1, $record->oneint);
2275         $this->assertEqual(1, $record->onenum);
2276         $this->assertEqual(1, $record->onechar);
2277         $this->assertEqual(1, $record->onetext);
2279         $record->oneint = false; // falses
2280         $record->onenum = false;
2281         $record->onechar = false;
2282         $record->onetext = false;
2283         $DB->update_record($tablename, $record);
2284         $record = $DB->get_record($tablename, array('course' => 2));
2285         $this->assertEqual(0, $record->oneint);
2286         $this->assertEqual(0, $record->onenum);
2287         $this->assertEqual(0, $record->onechar);
2288         $this->assertEqual(0, $record->onetext);
2290         // Check string data causes exception in numeric types
2291         $record->oneint = 'onestring';
2292         $record->onenum = 0;
2293         try {
2294             $DB->update_record($tablename, $record);
2295             $this->fail("Expecting an exception, none occurred");
2296         } catch (exception $e) {
2297             $this->assertTrue($e instanceof dml_exception);
2298         }
2299         $record->oneint = 0;
2300         $record->onenum = 'onestring';
2301         try {
2302             $DB->update_record($tablename, $record);
2303             $this->fail("Expecting an exception, none occurred");
2304         } catch (exception $e) {
2305             $this->assertTrue($e instanceof dml_exception);
2306         }
2308         // Check empty string data is stored as 0 in numeric datatypes
2309         $record->oneint = ''; // empty string
2310         $record->onenum = 0;
2311         $DB->update_record($tablename, $record);
2312         $record = $DB->get_record($tablename, array('course' => 2));
2313         $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
2315         $record->oneint = 0;
2316         $record->onenum = ''; // empty string
2317         $DB->update_record($tablename, $record);
2318         $record = $DB->get_record($tablename, array('course' => 2));
2319         $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
2321         // Check empty strings are set properly in string types
2322         $record->oneint = 0;
2323         $record->onenum = 0;
2324         $record->onechar = '';
2325         $record->onetext = '';
2326         $DB->update_record($tablename, $record);
2327         $record = $DB->get_record($tablename, array('course' => 2));
2328         $this->assertTrue($record->onechar === '');
2329         $this->assertTrue($record->onetext === '');
2331         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
2332         $record->oneint = ((210.10 + 39.92) - 150.02);
2333         $record->onenum = ((210.10 + 39.92) - 150.02);
2334         $DB->update_record($tablename, $record);
2335         $record = $DB->get_record($tablename, array('course' => 2));
2336         $this->assertEqual(100, $record->oneint);
2337         $this->assertEqual(100, $record->onenum);
2339         // Check various quotes/backslashes combinations in string types
2340         $teststrings = array(
2341             'backslashes and quotes alone (even): "" \'\' \\\\',
2342             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2343             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2344             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2345         foreach ($teststrings as $teststring) {
2346             $record->onechar = $teststring;
2347             $record->onetext = $teststring;
2348             $DB->update_record($tablename, $record);
2349             $record = $DB->get_record($tablename, array('course' => 2));
2350             $this->assertEqual($teststring, $record->onechar);
2351             $this->assertEqual($teststring, $record->onetext);
2352         }
2354         // Check LOBs in text/binary columns
2355         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
2356         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
2357         $record->onetext = $clob;
2358         $record->onebinary = $blob;
2359         $DB->update_record($tablename, $record);
2360         $record = $DB->get_record($tablename, array('course' => 2));
2361         $this->assertEqual($clob, $record->onetext, 'Test CLOB update (full contents output disabled)');
2362         $this->assertEqual($blob, $record->onebinary, 'Test BLOB update (full contents output disabled)');
2364         // And "small" LOBs too, just in case
2365         $newclob = substr($clob, 0, 500);
2366         $newblob = substr($blob, 0, 250);
2367         $record->onetext = $newclob;
2368         $record->onebinary = $newblob;
2369         $DB->update_record($tablename, $record);
2370         $record = $DB->get_record($tablename, array('course' => 2));
2371         $this->assertEqual($newclob, $record->onetext, 'Test "small" CLOB update (full contents output disabled)');
2372         $this->assertEqual($newblob, $record->onebinary, 'Test "small" BLOB update (full contents output disabled)');
2374         // Test saving a float in a CHAR column, and reading it back.
2375         $id = $DB->insert_record($tablename, array('onechar' => 'X'));
2376         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1.0));
2377         $this->assertEqual(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2378         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e20));
2379         $this->assertEqual(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2380         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-4));
2381         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2382         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-5));
2383         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2384         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-300));
2385         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2386         $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e300));
2387         $this->assertEqual(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2389         // Test saving a float in a TEXT column, and reading it back.
2390         $id = $DB->insert_record($tablename, array('onetext' => 'X'));
2391         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1.0));
2392         $this->assertEqual(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2393         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e20));
2394         $this->assertEqual(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2395         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-4));
2396         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2397         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-5));
2398         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2399         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-300));
2400         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2401         $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e300));
2402         $this->assertEqual(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2403     }
2405     public function test_set_field() {
2406         $DB = $this->tdb;
2407         $dbman = $DB->get_manager();
2409         $table = $this->get_test_table();
2410         $tablename = $table->getName();
2412         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2413         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2414         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
2415         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2416         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2417         $dbman->create_table($table);
2419         // simple set_field
2420         $id1 = $DB->insert_record($tablename, array('course' => 1));
2421         $id2 = $DB->insert_record($tablename, array('course' => 1));
2422         $id3 = $DB->insert_record($tablename, array('course' => 3));
2423         $this->assertTrue($DB->set_field($tablename, 'course', 2, array('id' => $id1)));
2424         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => $id1)));
2425         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
2426         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2427         $DB->delete_records($tablename, array());
2429         // multiple fields affected
2430         $id1 = $DB->insert_record($tablename, array('course' => 1));
2431         $id2 = $DB->insert_record($tablename, array('course' => 1));
2432         $id3 = $DB->insert_record($tablename, array('course' => 3));
2433         $DB->set_field($tablename, 'course', '5', array('course' => 1));
2434         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
2435         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
2436         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2437         $DB->delete_records($tablename, array());
2439         // no field affected
2440         $id1 = $DB->insert_record($tablename, array('course' => 1));
2441         $id2 = $DB->insert_record($tablename, array('course' => 1));
2442         $id3 = $DB->insert_record($tablename, array('course' => 3));
2443         $DB->set_field($tablename, 'course', '5', array('course' => 0));
2444         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id1)));
2445         $this->assertEqual(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
2446         $this->assertEqual(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2447         $DB->delete_records($tablename, array());
2449         // all fields - no condition
2450         $id1 = $DB->insert_record($tablename, array('course' => 1));
2451         $id2 = $DB->insert_record($tablename, array('course' => 1));
2452         $id3 = $DB->insert_record($tablename, array('course' => 3));
2453         $DB->set_field($tablename, 'course', 5, array());
2454         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
2455         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
2456         $this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id3)));
2458         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2459         $conditions = array('onetext' => '1');
2460         try {
2461             $DB->set_field($tablename, 'onechar', 'frog', $conditions);
2462             $this->fail('An Exception is missing, expected due to equating of text fields');
2463         } catch (exception $e) {
2464             $this->assertTrue($e instanceof dml_exception);
2465             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2466         }
2468         // Test saving a float in a CHAR column, and reading it back.
2469         $id = $DB->insert_record($tablename, array('onechar' => 'X'));
2470         $DB->set_field($tablename, 'onechar', 1.0, array('id' => $id));
2471         $this->assertEqual(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2472         $DB->set_field($tablename, 'onechar', 1e20, array('id' => $id));
2473         $this->assertEqual(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2474         $DB->set_field($tablename, 'onechar', 1e-4, array('id' => $id));
2475         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2476         $DB->set_field($tablename, 'onechar', 1e-5, array('id' => $id));
2477         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2478         $DB->set_field($tablename, 'onechar', 1e-300, array('id' => $id));
2479         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2480         $DB->set_field($tablename, 'onechar', 1e300, array('id' => $id));
2481         $this->assertEqual(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2483         // Test saving a float in a TEXT column, and reading it back.
2484         $id = $DB->insert_record($tablename, array('onetext' => 'X'));
2485         $DB->set_field($tablename, 'onetext', 1.0, array('id' => $id));
2486         $this->assertEqual(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2487         $DB->set_field($tablename, 'onetext', 1e20, array('id' => $id));
2488         $this->assertEqual(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2489         $DB->set_field($tablename, 'onetext', 1e-4, array('id' => $id));
2490         $this->assertEqual(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2491         $DB->set_field($tablename, 'onetext', 1e-5, array('id' => $id));
2492         $this->assertEqual(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2493         $DB->set_field($tablename, 'onetext', 1e-300, array('id' => $id));
2494         $this->assertEqual(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2495         $DB->set_field($tablename, 'onetext', 1e300, array('id' => $id));
2496         $this->assertEqual(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2498         // Note: All the nulls, booleans, empties, quoted and backslashes tests
2499         // go to set_field_select() because set_field() is just one wrapper over it
2500     }
2502     public function test_set_field_select() {
2504         // All the information in this test is fetched from DB by get_field() so we
2505         // have such method properly tested against nulls, empties and friends...
2507         $DB = $this->tdb;
2508         $dbman = $DB->get_manager();
2510         $table = $this->get_test_table();
2511         $tablename = $table->getName();
2513         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2514         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2515         $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null);
2516         $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null);
2517         $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
2518         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2519         $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2520         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2521         $dbman->create_table($table);
2523         $DB->insert_record($tablename, array('course' => 1));
2525         $this->assertTrue($DB->set_field_select($tablename, 'course', 2, 'id = ?', array(1)));
2526         $this->assertEqual(2, $DB->get_field($tablename, 'course', array('id' => 1)));
2528         // Check nulls are set properly for all types
2529         $DB->set_field_select($tablename, 'oneint', null, 'id = ?', array(1)); // trues
2530         $DB->set_field_select($tablename, 'onenum', null, 'id = ?', array(1));
2531         $DB->set_field_select($tablename, 'onechar', null, 'id = ?', array(1));
2532         $DB->set_field_select($tablename, 'onetext', null, 'id = ?', array(1));
2533         $DB->set_field_select($tablename, 'onebinary', null, 'id = ?', array(1));
2534         $this->assertNull($DB->get_field($tablename, 'oneint', array('id' => 1)));
2535         $this->assertNull($DB->get_field($tablename, 'onenum', array('id' => 1)));
2536         $this->assertNull($DB->get_field($tablename, 'onechar', array('id' => 1)));
2537         $this->assertNull($DB->get_field($tablename, 'onetext', array('id' => 1)));
2538         $this->assertNull($DB->get_field($tablename, 'onebinary', array('id' => 1)));
2540         // Check zeros are set properly for all types
2541         $DB->set_field_select($tablename, 'oneint', 0, 'id = ?', array(1));
2542         $DB->set_field_select($tablename, 'onenum', 0, 'id = ?', array(1));
2543         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2544         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2546         // Check booleans are set properly for all types
2547         $DB->set_field_select($tablename, 'oneint', true, 'id = ?', array(1)); // trues
2548         $DB->set_field_select($tablename, 'onenum', true, 'id = ?', array(1));
2549         $DB->set_field_select($tablename, 'onechar', true, 'id = ?', array(1));
2550         $DB->set_field_select($tablename, 'onetext', true, 'id = ?', array(1));
2551         $this->assertEqual(1, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2552         $this->assertEqual(1, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2553         $this->assertEqual(1, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2554         $this->assertEqual(1, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2556         $DB->set_field_select($tablename, 'oneint', false, 'id = ?', array(1)); // falses
2557         $DB->set_field_select($tablename, 'onenum', false, 'id = ?', array(1));
2558         $DB->set_field_select($tablename, 'onechar', false, 'id = ?', array(1));
2559         $DB->set_field_select($tablename, 'onetext', false, 'id = ?', array(1));
2560         $this->assertEqual(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2561         $this->assertEqual(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2562         $this->assertEqual(0, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2563         $this->assertEqual(0, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2565         // Check string data causes exception in numeric types
2566         try {
2567             $DB->set_field_select($tablename, 'oneint', 'onestring', 'id = ?', array(1));
2568             $this->fail("Expecting an exception, none occurred");
2569         } catch (exception $e) {
2570             $this->assertTrue($e instanceof dml_exception);
2571         }
2572         try {
2573             $DB->set_field_select($tablename, 'onenum', 'onestring', 'id = ?', array(1));
2574             $this->fail("Expecting an exception, none occurred");
2575         } catch (exception $e) {
2576             $this->assertTrue($e instanceof dml_exception);
2577         }
2579         // Check empty string data is stored as 0 in numeric datatypes
2580         $DB->set_field_select($tablename, 'oneint', '', 'id = ?', array(1));
2581         $field = $DB->get_field($tablename, 'oneint', array('id' => 1));
2582         $this->assertTrue(is_numeric($field) && $field == 0);
2584         $DB->set_field_select($tablename, 'onenum', '', 'id = ?', array(1));
2585         $field = $DB->get_field($tablename, 'onenum', array('id' => 1));
2586         $this->assertTrue(is_numeric($field) && $field == 0);
2588         // Check empty strings are set properly in string types
2589         $DB->set_field_select($tablename, 'onechar', '', 'id = ?', array(1));
2590         $DB->set_field_select($tablename, 'onetext', '', 'id = ?', array(1));
2591         $this->assertTrue($DB->get_field($tablename, 'onechar', array('id' => 1)) === '');
2592         $this->assertTrue($DB->get_field($tablename, 'onetext', array('id' => 1)) === '');
2594         // Check operation ((210.10 + 39.92) - 150.02) against numeric types
2595         $DB->set_field_select($tablename, 'oneint', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
2596         $DB->set_field_select($tablename, 'onenum', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
2597         $this->assertEqual(100, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2598         $this->assertEqual(100, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2600         // Check various quotes/backslashes combinations in string types
2601         $teststrings = array(
2602             'backslashes and quotes alone (even): "" \'\' \\\\',
2603             'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2604             'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2605             'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2606         foreach ($teststrings as $teststring) {
2607             $DB->set_field_select($tablename, 'onechar', $teststring, 'id = ?', array(1));
2608             $DB->set_field_select($tablename, 'onetext', $teststring, 'id = ?', array(1));
2609             $this->assertEqual($teststring, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2610             $this->assertEqual($teststring, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2611         }
2613         // Check LOBs in text/binary columns
2614         $clob = file_get_contents(dirname(__FILE__).'/fixtures/clob.txt');
2615         $blob = file_get_contents(dirname(__FILE__).'/fixtures/randombinary');
2616         $DB->set_field_select($tablename, 'onetext', $clob, 'id = ?', array(1));
2617         $DB->set_field_select($tablename, 'onebinary', $blob, 'id = ?', array(1));
2618         $this->assertEqual($clob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test CLOB set_field (full contents output disabled)');
2619         $this->assertEqual($blob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test BLOB set_field (full contents output disabled)');
2621         // And "small" LOBs too, just in case
2622         $newclob = substr($clob, 0, 500);
2623         $newblob = substr($blob, 0, 250);
2624         $DB->set_field_select($tablename, 'onetext', $newclob, 'id = ?', array(1));
2625         $DB->set_field_select($tablename, 'onebinary', $newblob, 'id = ?', array(1));
2626         $this->assertEqual($newclob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test "small" CLOB set_field (full contents output disabled)');
2627         $this->assertEqual($newblob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test "small" BLOB set_field (full contents output disabled)');
2629         // This is the failure from MDL-24863. This was giving an error on MSSQL,
2630         // which converts the '1' to an integer, which cannot then be compared with
2631         // onetext cast to a varchar. This should be fixed and working now.
2632         $newchar = 'frog';
2633         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2634         $params = array('onetext' => '1');
2635         try {
2636             $DB->set_field_select($tablename, 'onechar', $newchar, $DB->sql_compare_text('onetext') . ' = ?', $params);
2637             $this->assertTrue(true, 'No exceptions thrown with numerical text param comparison for text field.');
2638         } catch (dml_exception $e) {
2639             $this->assertFalse(true, 'We have an unexpected exception.');
2640             throw $e;
2641         }
2644     }
2646     public function test_count_records() {
2647         $DB = $this->tdb;
2649         $dbman = $DB->get_manager();
2651         $table = $this->get_test_table();
2652         $tablename = $table->getName();
2654         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2655         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2656         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2657         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2658         $dbman->create_table($table);
2660         $this->assertEqual(0, $DB->count_records($tablename));
2662         $DB->insert_record($tablename, array('course' => 3));
2663         $DB->insert_record($tablename, array('course' => 4));
2664         $DB->insert_record($tablename, array('course' => 5));
2666         $this->assertEqual(3, $DB->count_records($tablename));
2668         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2669         $conditions = array('onetext' => '1');
2670         try {
2671             $DB->count_records($tablename, $conditions);
2672             $this->fail('An Exception is missing, expected due to equating of text fields');
2673         } catch (exception $e) {
2674             $this->assertTrue($e instanceof dml_exception);
2675             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2676         }
2677     }
2679     public function test_count_records_select() {
2680         $DB = $this->tdb;
2682         $dbman = $DB->get_manager();
2684         $table = $this->get_test_table();
2685         $tablename = $table->getName();
2687         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2688         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2689         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2690         $dbman->create_table($table);
2692         $this->assertEqual(0, $DB->count_records($tablename));
2694         $DB->insert_record($tablename, array('course' => 3));
2695         $DB->insert_record($tablename, array('course' => 4));
2696         $DB->insert_record($tablename, array('course' => 5));
2698         $this->assertEqual(2, $DB->count_records_select($tablename, 'course > ?', array(3)));
2699     }
2701     public function test_count_records_sql() {
2702         $DB = $this->tdb;
2703         $dbman = $DB->get_manager();
2705         $table = $this->get_test_table();
2706         $tablename = $table->getName();
2708         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2709         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2710         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2711         $dbman->create_table($table);
2713         $this->assertEqual(0, $DB->count_records($tablename));
2715         $DB->insert_record($tablename, array('course' => 3));
2716         $DB->insert_record($tablename, array('course' => 4));
2717         $DB->insert_record($tablename, array('course' => 5));
2719         $this->assertEqual(2, $DB->count_records_sql("SELECT COUNT(*) FROM {{$tablename}} WHERE course > ?", array(3)));
2720     }
2722     public function test_record_exists() {
2723         $DB = $this->tdb;
2724         $dbman = $DB->get_manager();
2726         $table = $this->get_test_table();
2727         $tablename = $table->getName();
2729         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2730         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2731         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2732         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2733         $dbman->create_table($table);
2735         $this->assertEqual(0, $DB->count_records($tablename));
2737         $this->assertFalse($DB->record_exists($tablename, array('course' => 3)));
2738         $DB->insert_record($tablename, array('course' => 3));
2740         $this->assertTrue($DB->record_exists($tablename, array('course' => 3)));
2743         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2744         $conditions = array('onetext' => '1');
2745         try {
2746             $DB->record_exists($tablename, $conditions);
2747             $this->fail('An Exception is missing, expected due to equating of text fields');
2748         } catch (exception $e) {
2749             $this->assertTrue($e instanceof dml_exception);
2750             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2751         }
2752     }
2754     public function test_record_exists_select() {
2755         $DB = $this->tdb;
2756         $dbman = $DB->get_manager();
2758         $table = $this->get_test_table();
2759         $tablename = $table->getName();
2761         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2762         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2763         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2764         $dbman->create_table($table);
2766         $this->assertEqual(0, $DB->count_records($tablename));
2768         $this->assertFalse($DB->record_exists_select($tablename, "course = ?", array(3)));
2769         $DB->insert_record($tablename, array('course' => 3));
2771         $this->assertTrue($DB->record_exists_select($tablename, "course = ?", array(3)));
2772     }
2774     public function test_record_exists_sql() {
2775         $DB = $this->tdb;
2776         $dbman = $DB->get_manager();
2778         $table = $this->get_test_table();
2779         $tablename = $table->getName();
2781         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2782         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2783         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2784         $dbman->create_table($table);
2786         $this->assertEqual(0, $DB->count_records($tablename));
2788         $this->assertFalse($DB->record_exists_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3)));
2789         $DB->insert_record($tablename, array('course' => 3));
2791         $this->assertTrue($DB->record_exists_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3)));
2792     }
2794     public function test_recordset_locks_delete() {
2795         $DB = $this->tdb;
2796         $dbman = $DB->get_manager();
2798         //Setup
2799         $table = $this->get_test_table();
2800         $tablename = $table->getName();
2802         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2803         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2804         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2805         $dbman->create_table($table);
2807         $DB->insert_record($tablename, array('course' => 1));
2808         $DB->insert_record($tablename, array('course' => 2));
2809         $DB->insert_record($tablename, array('course' => 3));
2810         $DB->insert_record($tablename, array('course' => 4));
2811         $DB->insert_record($tablename, array('course' => 5));
2812         $DB->insert_record($tablename, array('course' => 6));
2814         // Test against db write locking while on an open recordset
2815         $rs = $DB->get_recordset($tablename, array(), null, 'course', 2, 2); // get courses = {3,4}
2816         foreach ($rs as $record) {
2817             $cid = $record->course;
2818             $DB->delete_records($tablename, array('course' => $cid));
2819             $this->assertFalse($DB->record_exists($tablename, array('course' => $cid)));
2820         }
2821         $rs->close();
2823         $this->assertEqual(4, $DB->count_records($tablename, array()));
2824     }
2826     public function test_recordset_locks_update() {
2827         $DB = $this->tdb;
2828         $dbman = $DB->get_manager();
2830         //Setup
2831         $table = $this->get_test_table();
2832         $tablename = $table->getName();
2834         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2835         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2836         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2837         $dbman->create_table($table);
2839         $DB->insert_record($tablename, array('course' => 1));
2840         $DB->insert_record($tablename, array('course' => 2));
2841         $DB->insert_record($tablename, array('course' => 3));
2842         $DB->insert_record($tablename, array('course' => 4));
2843         $DB->insert_record($tablename, array('course' => 5));
2844         $DB->insert_record($tablename, array('course' => 6));
2846         // Test against db write locking while on an open recordset
2847         $rs = $DB->get_recordset($tablename, array(), null, 'course', 2, 2); // get courses = {3,4}
2848         foreach ($rs as $record) {
2849             $cid = $record->course;
2850             $DB->set_field($tablename, 'course', 10, array('course' => $cid));
2851             $this->assertFalse($DB->record_exists($tablename, array('course' => $cid)));
2852         }
2853         $rs->close();
2855         $this->assertEqual(2, $DB->count_records($tablename, array('course' => 10)));
2856     }
2858     public function test_delete_records() {
2859         $DB = $this->tdb;
2860         $dbman = $DB->get_manager();
2862         $table = $this->get_test_table();
2863         $tablename = $table->getName();
2865         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2866         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2867         $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2868         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2869         $dbman->create_table($table);
2871         $DB->insert_record($tablename, array('course' => 3));
2872         $DB->insert_record($tablename, array('course' => 2));
2873         $DB->insert_record($tablename, array('course' => 2));
2875         // Delete all records
2876         $this->assertTrue($DB->delete_records($tablename));
2877         $this->assertEqual(0, $DB->count_records($tablename));
2879         // Delete subset of records
2880         $DB->insert_record($tablename, array('course' => 3));
2881         $DB->insert_record($tablename, array('course' => 2));
2882         $DB->insert_record($tablename, array('course' => 2));
2884         $this->assertTrue($DB->delete_records($tablename, array('course' => 2)));
2885         $this->assertEqual(1, $DB->count_records($tablename));
2887         // delete all
2888         $this->assertTrue($DB->delete_records($tablename, array()));
2889         $this->assertEqual(0, $DB->count_records($tablename));
2891         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2892         $conditions = array('onetext'=>'1');
2893         try {
2894             $DB->delete_records($tablename, $conditions);
2895             $this->fail('An Exception is missing, expected due to equating of text fields');
2896         } catch (exception $e) {
2897             $this->assertTrue($e instanceof dml_exception);
2898             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2899         }
2901         // test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
2902         $conditions = array('onetext' => 1);
2903         try {
2904             $DB->delete_records($tablename, $conditions);
2905             $this->fail('An Exception is missing, expected due to equating of text fields');
2906         } catch (exception $e) {
2907             $this->assertTrue($e instanceof dml_exception);
2908             $this->assertEqual($e->errorcode, 'textconditionsnotallowed');
2909         }
2910     }
2912     public function test_delete_records_select() {
2913         $DB = $this->tdb;
2914         $dbman = $DB->get_manager();
2916         $table = $this->get_test_table();
2917         $tablename = $table->getName();
2919         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2920         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2921         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2922         $dbman->create_table($table);
2924         $DB->insert_record($tablename, array('course' => 3));
2925         $DB->insert_record($tablename, array('course' => 2));
2926         $DB->insert_record($tablename, array('course' => 2));
2928         $this->assertTrue($DB->delete_records_select($tablename, 'course = ?', array(2)));
2929         $this->assertEqual(1, $DB->count_records($tablename));
2930     }
2932     public function test_delete_records_list() {
2933         $DB = $this->tdb;
2934         $dbman = $DB->get_manager();
2936         $table = $this->get_test_table();
2937         $tablename = $table->getName();
2939         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2940         $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2941         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2942         $dbman->create_table($table);
2944         $DB->insert_record($tablename, array('course' => 1));
2945         $DB->insert_record($tablename, array('course' => 2));
2946         $DB->insert_record($tablename, array('course' => 3));
2948         $this->assertTrue($DB->delete_records_list($tablename, 'course', array(2, 3)));
2949         $this->assertEqual(1, $DB->count_records($tablename));
2951         $this->assertTrue($DB->delete_records_list($tablename, 'course', array())); /// Must delete 0 rows without conditions. MDL-17645
2952         $this->assertEqual(1, $DB->count_records($tablename));
2953     }
2955     function test_sql_null_from_clause() {
2956         $DB = $this->tdb;
2957         $sql = "SELECT 1 AS id ".$DB->sql_null_from_clause();
2958         $this->assertEqual($DB->get_field_sql($sql), 1);
2959     }
2961     function test_sql_bitand() {
2962         $DB = $this->tdb;
2963         $dbman = $DB->get_manager();
2965         $table = $this->get_test_table();
2966         $tablename = $table->getName();
2968         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2969         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2970         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
2971         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2972         $dbman->create_table($table);
2974         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
2976         $sql = "SELECT ".$DB->sql_bitand(10, 3)." AS res ".$DB->sql_null_from_clause();
2977         $this->assertEqual($DB->get_field_sql($sql), 2);
2979         $sql = "SELECT id, ".$DB->sql_bitand('col1', 'col2')." AS res FROM {{$tablename}}";
2980         $result = $DB->get_records_sql($sql);
2981         $this->assertEqual(count($result), 1);
2982         $this->assertEqual(reset($result)->res, 2);
2984         $sql = "SELECT id, ".$DB->sql_bitand('col1', '?')." AS res FROM {{$tablename}}";
2985         $result = $DB->get_records_sql($sql, array(10));
2986         $this->assertEqual(count($result), 1);
2987         $this->assertEqual(reset($result)->res, 2);
2988     }
2990     function test_sql_bitnot() {
2991         $DB = $this->tdb;
2993         $not = $DB->sql_bitnot(2);
2994         $notlimited = $DB->sql_bitand($not, 7); // might be positive or negative number which can not fit into PHP INT!
2996         $sql = "SELECT $notlimited AS res ".$DB->sql_null_from_clause();
2997         $this->assertEqual($DB->get_field_sql($sql), 5);
2998     }
3000     function test_sql_bitor() {
3001         $DB = $this->tdb;
3002         $dbman = $DB->get_manager();
3004         $table = $this->get_test_table();
3005         $tablename = $table->getName();
3007         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3008         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3009         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3010         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3011         $dbman->create_table($table);
3013         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
3015         $sql = "SELECT ".$DB->sql_bitor(10, 3)." AS res ".$DB->sql_null_from_clause();
3016         $this->assertEqual($DB->get_field_sql($sql), 11);
3018         $sql = "SELECT id, ".$DB->sql_bitor('col1', 'col2')." AS res FROM {{$tablename}}";
3019         $result = $DB->get_records_sql($sql);
3020         $this->assertEqual(count($result), 1);
3021         $this->assertEqual(reset($result)->res, 11);
3023         $sql = "SELECT id, ".$DB->sql_bitor('col1', '?')." AS res FROM {{$tablename}}";
3024         $result = $DB->get_records_sql($sql, array(10));
3025         $this->assertEqual(count($result), 1);
3026         $this->assertEqual(reset($result)->res, 11);
3027     }
3029     function test_sql_bitxor() {
3030         $DB = $this->tdb;
3031         $dbman = $DB->get_manager();
3033         $table = $this->get_test_table();
3034         $tablename = $table->getName();
3036         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3037         $table->add_field('col1', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3038         $table->add_field('col2', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3039         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3040         $dbman->create_table($table);
3042         $DB->insert_record($tablename, array('col1' => 3, 'col2' => 10));
3044         $sql = "SELECT ".$DB->sql_bitxor(10, 3)." AS res ".$DB->sql_null_from_clause();
3045         $this->assertEqual($DB->get_field_sql($sql), 9);
3047         $sql = "SELECT id, ".$DB->sql_bitxor('col1', 'col2')." AS res FROM {{$tablename}}";
3048         $result = $DB->get_records_sql($sql);
3049         $this->assertEqual(count($result), 1);
3050         $this->assertEqual(reset($result)->res, 9);
3052         $sql = "SELECT id, ".$DB->sql_bitxor('col1', '?')." AS res FROM {{$tablename}}";
3053         $result = $DB->get_records_sql($sql, array(10));
3054         $this->assertEqual(count($result), 1);
3055         $this->assertEqual(reset($result)->res, 9);
3056     }
3058     function test_sql_modulo() {
3059         $DB = $this->tdb;
3060         $sql = "SELECT ".$DB->sql_modulo(10, 7)." AS res ".$DB->sql_null_from_clause();
3061         $this->assertEqual($DB->get_field_sql($sql), 3);
3062     }
3064     function test_sql_ceil() {
3065         $DB = $this->tdb;
3066         $sql = "SELECT ".$DB->sql_ceil(665.666)." AS res ".$DB->sql_null_from_clause();
3067         $this->assertEqual($DB->get_field_sql($sql), 666);
3068     }
3070     function test_cast_char2int() {
3071         $DB = $this->tdb;
3072         $dbman = $DB->get_manager();
3074         $table1 = $this->get_test_table("1");
3075         $tablename1 = $table1->getName();
3077         $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3078         $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3079         $table1->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
3080         $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3081         $dbman->create_table($table1);
3083         $DB->insert_record($tablename1, array('name'=>'0100', 'nametext'=>'0200'));
3084         $DB->insert_record($tablename1, array('name'=>'10',   'nametext'=>'20'));
3086         $table2 = $this->get_test_table("2");
3087         $tablename2 = $table2->getName();
3088         $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3089         $table2->add_field('res', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3090         $table2->add_field('restext', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
3091         $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3092         $dbman->create_table($table2);
3094         $DB->insert_record($tablename2, array('res'=>100, 'restext'=>200));
3096         // casting varchar field
3097         $sql = "SELECT *
3098                   FROM {".$tablename1."} t1
3099                   JOIN {".$tablename2."} t2 ON ".$DB->sql_cast_char2int("t1.name")." = t2.res ";
3100         $records = $DB->get_records_sql($sql);
3101         $this->assertEqual(count($records), 1);
3102         // also test them in order clauses
3103         $sql = "SELECT * FROM {{$tablename1}} ORDER BY ".$DB->sql_cast_char2int('name');
3104         $records = $DB->get_records_sql($sql);
3105         $this->assertEqual(count($records), 2);
3106         $this->assertEqual(reset($records)->name, '10');
3107         $this->assertEqual(next($records)->name, '0100');
3109         // casting text field
3110         $sql = "SELECT *
3111                   FROM {".$tablename1."} t1
3112                   JOIN {".$tablename2."} t2 ON ".$DB->sql_cast_char2int("t1.nametext", true)." = t2.restext ";
3113         $records = $DB->get_records_sql($sql);
3114         $this->assertEqual(count($records), 1);
3115         // also test them in order clauses
3116         $sql = "SELECT * FROM {{$tablename1}} ORDER BY ".$DB->sql_cast_char2int('nametext', true);
3117         $records = $DB->get_records_sql($sql);
3118         $this->assertEqual(count($records), 2);
3119         $this->assertEqual(reset($records)->nametext, '20');
3120         $this->assertEqual(next($records)->nametext, '0200');
3121     }
3123     function test_cast_char2real() {
3124         $DB = $this->tdb;
3125         $dbman = $DB->get_manager();
3127         $table = $this->get_test_table();
3128         $tablename = $table->getName();
3130         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3131         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3132         $table->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
3133         $table->add_field('res', XMLDB_TYPE_NUMBER, '12, 7', null, null, null, null);
3134         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3135         $dbman->create_table($table);
3137         $DB->insert_record($tablename, array('name'=>'10.10', 'nametext'=>'10.10', 'res'=>5.1));
3138         $DB->insert_record($tablename, array('name'=>'91.10', 'nametext'=>'91.10', 'res'=>666));
3139         $DB->insert_record($tablename, array('name'=>'011.10','nametext'=>'011.10','res'=>10.1));
3141         // casting varchar field
3142         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_cast_char2real('name')." > res";
3143         $records = $DB->get_records_sql($sql);
3144         $this->assertEqual(count($records), 2);
3145         // also test them in order clauses
3146         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_cast_char2real('name');
3147         $records = $DB->get_records_sql($sql);
3148         $this->assertEqual(count($records), 3);
3149         $this->assertEqual(reset($records)->name, '10.10');
3150         $this->assertEqual(next($records)->name, '011.10');
3151         $this->assertEqual(next($records)->name, '91.10');
3153         // casting text field
3154         $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_cast_char2real('nametext', true)." > res";
3155         $records = $DB->get_records_sql($sql);
3156         $this->assertEqual(count($records), 2);
3157         // also test them in order clauses
3158         $sql = "SELECT * FROM {{$tablename}} ORDER BY ".$DB->sql_cast_char2real('nametext', true);
3159         $records = $DB->get_records_sql($sql);
3160         $this->assertEqual(count($records), 3);
3161         $this->assertEqual(reset($records)->nametext, '10.10');
3162         $this->assertEqual(next($records)->nametext, '011.10');
3163         $this->assertEqual(next($records)->nametext, '91.10');
3164     }
3166     function sql_compare_text() {
3167         $DB = $this->tdb;
3168         $dbman = $DB->get_manager();
3170         $table = $this->get_test_table();
3171         $tablename = $table->getName();
3173         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3174         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3175         $table->add_field('description', XMLDB_TYPE_TEXT, 'big', null, null, null, null);
3176         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3177         $dbman->create_table($table);
3179         $DB->insert_record($tablename, array('name'=>'abcd',   'description'=>'abcd'));
3180         $DB->insert_record($tablename, array('name'=>'abcdef', 'description'=>'bbcdef'));
3181         $DB->insert_record($tablename, array('name'=>'aaaabb', 'description'=>'aaaacccccccccccccccccc'));
3183         $sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description');
3184         $records = $DB->get_records_sql($sql);
3185         $this->assertEqual(count($records), 1);
3187         $sql = "SELECT * FROM {{$tablename}} WHERE name = ".$DB->sql_compare_text('description', 4);
3188         $records = $DB->get_records_sql($sql);
3189         $this->assertEqual(count($records), 2);
3190     }
3192     function test_unique_index_collation_trouble() {
3193         // note: this is a work in progress, we should probably move this to ddl test
3195         $DB = $this->tdb;
3196         $dbman = $DB->get_manager();
3198         $table = $this->get_test_table();
3199         $tablename = $table->getName();
3201         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3202         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3203         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3204         $table->add_index('name', XMLDB_INDEX_UNIQUE, array('name'));
3205         $dbman->create_table($table);
3207         $DB->insert_record($tablename, array('name'=>'aaa'));
3209         try {
3210             $DB->insert_record($tablename, array('name'=>'AAA'));
3211         } catch (Exception $e) {
3212             //TODO: ignore case insensitive uniqueness problems for now
3213             //$this->fail("Unique index is case sensitive - this may cause problems in some tables");
3214         }
3216         try {
3217             $DB->insert_record($tablename, array('name'=>'aäa'));
3218             $DB->insert_record($tablename, array('name'=>'aáa'));
3219             $this->assertTrue(true);
3220         } catch (Exception $e) {
3221             $family = $DB->get_dbfamily();
3222             if ($family === 'mysql' or $family === 'mssql') {
3223                 $this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages. This is usually caused by accent insensitive default collation.");
3224             } else {
3225                 // this should not happen, PostgreSQL and Oracle do not support accent insensitive uniqueness.
3226                 $this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages.");
3227             }
3228             throw($e);
3229         }
3230     }
3232     function test_sql_binary_equal() {
3233         $DB = $this->tdb;
3234         $dbman = $DB->get_manager();
3236         $table = $this->get_test_table();
3237         $tablename = $table->getName();
3239         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3240         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3241         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3242         $dbman->create_table($table);
3244         $DB->insert_record($tablename, array('name'=>'aaa'));
3245         $DB->insert_record($tablename, array('name'=>'aáa'));
3246         $DB->insert_record($tablename, array('name'=>'aäa'));
3247         $DB->insert_record($tablename, array('name'=>'bbb'));
3248         $DB->insert_record($tablename, array('name'=>'BBB'));
3250         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('aaa'));
3251         $this->assertEqual(count($records), 1, 'SQL operator "=" is expected to be accent sensitive');
3253         $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('bbb'));
3254         $this->assertEqual(count($records), 1, 'SQL operator "=" is expected to be case sensitive');
3255     }
3257     function test_sql_like() {
3258         $DB = $this->tdb;
3259         $dbman = $DB->get_manager();
3261         $table = $this->get_test_table();
3262         $tablename = $table->getName();
3264         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3265         $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
3266         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3267         $dbman->create_table($table);