MDL-43882 dml: New test for perf_get_xxxx() methods
[moodle.git] / lib / dml / tests / dml_test.php
CommitLineData
a3d5830a
PS
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
9d6d32b6 18 * DML layer tests.
a3d5830a 19 *
00902cd9 20 * @package core_dml
a3d5830a
PS
21 * @category phpunit
22 * @copyright 2008 Nicolas Connault
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die();
27
8252b7c2 28class core_dml_testcase extends database_driver_testcase {
a3d5830a 29
4787e466
PS
30 protected function setUp() {
31 parent::setUp();
9d6d32b6 32 $dbman = $this->tdb->get_manager(); // Loads DDL libs.
4787e466
PS
33 }
34
a3d5830a
PS
35 /**
36 * Get a xmldb_table object for testing, deleting any existing table
37 * of the same name, for example if one was left over from a previous test
38 * run that crashed.
39 *
40 * @param string $suffix table name suffix, use if you need more test tables
41 * @return xmldb_table the table object.
42 */
43 private function get_test_table($suffix = '') {
44 $tablename = "test_table";
45 if ($suffix !== '') {
46 $tablename .= $suffix;
47 }
48
49 $table = new xmldb_table($tablename);
50 $table->setComment("This is a test'n drop table. You can drop it safely");
51 return new xmldb_table($tablename);
52 }
53
9d6d32b6 54 public function test_diagnose() {
a3d5830a
PS
55 $DB = $this->tdb;
56 $result = $DB->diagnose();
57 $this->assertNull($result, 'Database self diagnostics failed %s');
58 }
59
9d6d32b6 60 public function test_get_server_info() {
a3d5830a
PS
61 $DB = $this->tdb;
62 $result = $DB->get_server_info();
9d6d32b6
PS
63 $this->assertInternalType('array', $result);
64 $this->assertArrayHasKey('description', $result);
65 $this->assertArrayHasKey('version', $result);
a3d5830a
PS
66 }
67
68 public function test_get_in_or_equal() {
69 $DB = $this->tdb;
70
9d6d32b6 71 // SQL_PARAMS_QM - IN or =.
a3d5830a 72
9d6d32b6 73 // Correct usage of multiple values.
a3d5830a
PS
74 $in_values = array('value1', 'value2', '3', 4, null, false, true);
75 list($usql, $params) = $DB->get_in_or_equal($in_values);
9d6d32b6 76 $this->assertSame('IN ('.implode(',', array_fill(0, count($in_values), '?')).')', $usql);
a3d5830a
PS
77 $this->assertEquals(count($in_values), count($params));
78 foreach ($params as $key => $value) {
79 $this->assertSame($in_values[$key], $value);
80 }
81
9d6d32b6 82 // Correct usage of single value (in an array).
a3d5830a
PS
83 $in_values = array('value1');
84 list($usql, $params) = $DB->get_in_or_equal($in_values);
85 $this->assertEquals("= ?", $usql);
9d6d32b6 86 $this->assertCount(1, $params);
a3d5830a
PS
87 $this->assertEquals($in_values[0], $params[0]);
88
9d6d32b6 89 // Correct usage of single value.
a3d5830a
PS
90 $in_value = 'value1';
91 list($usql, $params) = $DB->get_in_or_equal($in_values);
92 $this->assertEquals("= ?", $usql);
9d6d32b6 93 $this->assertCount(1, $params);
a3d5830a
PS
94 $this->assertEquals($in_value, $params[0]);
95
9d6d32b6 96 // SQL_PARAMS_QM - NOT IN or <>.
a3d5830a 97
9d6d32b6 98 // Correct usage of multiple values.
a3d5830a
PS
99 $in_values = array('value1', 'value2', 'value3', 'value4');
100 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
101 $this->assertEquals("NOT IN (?,?,?,?)", $usql);
9d6d32b6 102 $this->assertCount(4, $params);
a3d5830a
PS
103 foreach ($params as $key => $value) {
104 $this->assertEquals($in_values[$key], $value);
105 }
106
9d6d32b6 107 // Correct usage of single value (in array().
a3d5830a
PS
108 $in_values = array('value1');
109 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
110 $this->assertEquals("<> ?", $usql);
9d6d32b6 111 $this->assertCount(1, $params);
a3d5830a
PS
112 $this->assertEquals($in_values[0], $params[0]);
113
9d6d32b6 114 // Correct usage of single value.
a3d5830a
PS
115 $in_value = 'value1';
116 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
117 $this->assertEquals("<> ?", $usql);
9d6d32b6 118 $this->assertCount(1, $params);
a3d5830a
PS
119 $this->assertEquals($in_value, $params[0]);
120
9d6d32b6 121 // SQL_PARAMS_NAMED - IN or =.
a3d5830a 122
9d6d32b6 123 // Correct usage of multiple values.
a3d5830a
PS
124 $in_values = array('value1', 'value2', 'value3', 'value4');
125 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
9d6d32b6 126 $this->assertCount(4, $params);
a3d5830a
PS
127 reset($in_values);
128 $ps = array();
129 foreach ($params as $key => $value) {
130 $this->assertEquals(current($in_values), $value);
131 next($in_values);
132 $ps[] = ':'.$key;
133 }
134 $this->assertEquals("IN (".implode(',', $ps).")", $usql);
135
9d6d32b6 136 // Correct usage of single values (in array).
a3d5830a
PS
137 $in_values = array('value1');
138 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
9d6d32b6 139 $this->assertCount(1, $params);
a3d5830a
PS
140 $value = reset($params);
141 $key = key($params);
142 $this->assertEquals("= :$key", $usql);
143 $this->assertEquals($in_value, $value);
144
9d6d32b6 145 // Correct usage of single value.
a3d5830a
PS
146 $in_value = 'value1';
147 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
9d6d32b6 148 $this->assertCount(1, $params);
a3d5830a
PS
149 $value = reset($params);
150 $key = key($params);
151 $this->assertEquals("= :$key", $usql);
152 $this->assertEquals($in_value, $value);
153
9d6d32b6 154 // SQL_PARAMS_NAMED - NOT IN or <>.
a3d5830a 155
9d6d32b6 156 // Correct usage of multiple values.
a3d5830a
PS
157 $in_values = array('value1', 'value2', 'value3', 'value4');
158 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
9d6d32b6 159 $this->assertCount(4, $params);
a3d5830a
PS
160 reset($in_values);
161 $ps = array();
162 foreach ($params as $key => $value) {
163 $this->assertEquals(current($in_values), $value);
164 next($in_values);
165 $ps[] = ':'.$key;
166 }
167 $this->assertEquals("NOT IN (".implode(',', $ps).")", $usql);
168
9d6d32b6 169 // Correct usage of single values (in array).
a3d5830a
PS
170 $in_values = array('value1');
171 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
9d6d32b6 172 $this->assertCount(1, $params);
a3d5830a
PS
173 $value = reset($params);
174 $key = key($params);
175 $this->assertEquals("<> :$key", $usql);
176 $this->assertEquals($in_value, $value);
177
9d6d32b6 178 // Correct usage of single value.
a3d5830a
PS
179 $in_value = 'value1';
180 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
9d6d32b6 181 $this->assertCount(1, $params);
a3d5830a
PS
182 $value = reset($params);
183 $key = key($params);
184 $this->assertEquals("<> :$key", $usql);
185 $this->assertEquals($in_value, $value);
186
9d6d32b6
PS
187 // Make sure the param names are unique.
188 list($usql1, $params1) = $DB->get_in_or_equal(array(1, 2, 3), SQL_PARAMS_NAMED, 'param');
189 list($usql2, $params2) = $DB->get_in_or_equal(array(1, 2, 3), SQL_PARAMS_NAMED, 'param');
a3d5830a
PS
190 $params1 = array_keys($params1);
191 $params2 = array_keys($params2);
192 $common = array_intersect($params1, $params2);
9d6d32b6 193 $this->assertCount(0, $common);
a3d5830a 194
9d6d32b6 195 // Some incorrect tests.
a3d5830a 196
9d6d32b6 197 // Incorrect usage passing not-allowed params type.
a3d5830a
PS
198 $in_values = array(1, 2, 3);
199 try {
200 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_DOLLAR, 'param', false);
201 $this->fail('An Exception is missing, expected due to not supported SQL_PARAMS_DOLLAR');
9d6d32b6
PS
202 } catch (moodle_exception $e) {
203 $this->assertInstanceOf('dml_exception', $e);
204 $this->assertSame('typenotimplement', $e->errorcode);
a3d5830a
PS
205 }
206
9d6d32b6 207 // Incorrect usage passing empty array.
a3d5830a
PS
208 $in_values = array();
209 try {
210 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
211 $this->fail('An Exception is missing, expected due to empty array of items');
9d6d32b6
PS
212 } catch (moodle_exception $e) {
213 $this->assertInstanceOf('coding_exception', $e);
a3d5830a
PS
214 }
215
9d6d32b6 216 // Test using $onemptyitems.
a3d5830a 217
9d6d32b6 218 // Correct usage passing empty array and $onemptyitems = null (equal = true, QM).
a3d5830a 219 $in_values = array();
9d6d32b6
PS
220 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, null);
221 $this->assertSame(' IS NULL', $usql);
a3d5830a
PS
222 $this->assertSame(array(), $params);
223
9d6d32b6 224 // Correct usage passing empty array and $onemptyitems = null (equal = false, NAMED).
a3d5830a 225 $in_values = array();
9d6d32b6
PS
226 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, null);
227 $this->assertSame(' IS NOT NULL', $usql);
a3d5830a
PS
228 $this->assertSame(array(), $params);
229
9d6d32b6 230 // Correct usage passing empty array and $onemptyitems = true (equal = true, QM).
a3d5830a
PS
231 $in_values = array();
232 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, true);
9d6d32b6 233 $this->assertSame('= ?', $usql);
a3d5830a
PS
234 $this->assertSame(array(true), $params);
235
9d6d32b6 236 // Correct usage passing empty array and $onemptyitems = true (equal = false, NAMED).
a3d5830a
PS
237 $in_values = array();
238 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, true);
9d6d32b6 239 $this->assertCount(1, $params);
a3d5830a
PS
240 $value = reset($params);
241 $key = key($params);
9d6d32b6 242 $this->assertSame('<> :'.$key, $usql);
a3d5830a
PS
243 $this->assertSame($value, true);
244
9d6d32b6 245 // Correct usage passing empty array and $onemptyitems = -1 (equal = true, QM).
a3d5830a
PS
246 $in_values = array();
247 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, -1);
9d6d32b6 248 $this->assertSame('= ?', $usql);
a3d5830a
PS
249 $this->assertSame(array(-1), $params);
250
9d6d32b6 251 // Correct usage passing empty array and $onemptyitems = -1 (equal = false, NAMED).
a3d5830a
PS
252 $in_values = array();
253 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, -1);
9d6d32b6 254 $this->assertCount(1, $params);
a3d5830a
PS
255 $value = reset($params);
256 $key = key($params);
9d6d32b6 257 $this->assertSame('<> :'.$key, $usql);
a3d5830a
PS
258 $this->assertSame($value, -1);
259
9d6d32b6 260 // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = true, QM).
a3d5830a
PS
261 $in_values = array();
262 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, 'onevalue');
9d6d32b6 263 $this->assertSame('= ?', $usql);
a3d5830a
PS
264 $this->assertSame(array('onevalue'), $params);
265
9d6d32b6 266 // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = false, NAMED).
a3d5830a
PS
267 $in_values = array();
268 list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, 'onevalue');
9d6d32b6 269 $this->assertCount(1, $params);
a3d5830a
PS
270 $value = reset($params);
271 $key = key($params);
9d6d32b6 272 $this->assertSame('<> :'.$key, $usql);
a3d5830a
PS
273 $this->assertSame($value, 'onevalue');
274 }
275
276 public function test_fix_table_names() {
277 $DB = new moodle_database_for_testing();
278 $prefix = $DB->get_prefix();
279
9d6d32b6 280 // Simple placeholder.
a3d5830a
PS
281 $placeholder = "{user_123}";
282 $this->assertSame($prefix."user_123", $DB->public_fix_table_names($placeholder));
283
9d6d32b6 284 // Wrong table name.
a3d5830a
PS
285 $placeholder = "{user-a}";
286 $this->assertSame($placeholder, $DB->public_fix_table_names($placeholder));
287
9d6d32b6 288 // Wrong table name.
a3d5830a
PS
289 $placeholder = "{123user}";
290 $this->assertSame($placeholder, $DB->public_fix_table_names($placeholder));
291
9d6d32b6 292 // Full SQL.
a3d5830a
PS
293 $sql = "SELECT * FROM {user}, {funny_table_name}, {mdl_stupid_table} WHERE {user}.id = {funny_table_name}.userid";
294 $expected = "SELECT * FROM {$prefix}user, {$prefix}funny_table_name, {$prefix}mdl_stupid_table WHERE {$prefix}user.id = {$prefix}funny_table_name.userid";
295 $this->assertSame($expected, $DB->public_fix_table_names($sql));
296 }
297
9d6d32b6 298 public function test_fix_sql_params() {
a3d5830a 299 $DB = $this->tdb;
c56cdae9 300 $prefix = $DB->get_prefix();
a3d5830a
PS
301
302 $table = $this->get_test_table();
303 $tablename = $table->getName();
304
9d6d32b6 305 // Correct table placeholder substitution.
a3d5830a
PS
306 $sql = "SELECT * FROM {{$tablename}}";
307 $sqlarray = $DB->fix_sql_params($sql);
c56cdae9 308 $this->assertEquals("SELECT * FROM {$prefix}".$tablename, $sqlarray[0]);
a3d5830a 309
9d6d32b6 310 // Conversions of all param types.
a3d5830a 311 $sql = array();
c56cdae9
312 $sql[SQL_PARAMS_NAMED] = "SELECT * FROM {$prefix}testtable WHERE name = :param1, course = :param2";
313 $sql[SQL_PARAMS_QM] = "SELECT * FROM {$prefix}testtable WHERE name = ?, course = ?";
314 $sql[SQL_PARAMS_DOLLAR] = "SELECT * FROM {$prefix}testtable WHERE name = \$1, course = \$2";
a3d5830a
PS
315
316 $params = array();
317 $params[SQL_PARAMS_NAMED] = array('param1'=>'first record', 'param2'=>1);
318 $params[SQL_PARAMS_QM] = array('first record', 1);
319 $params[SQL_PARAMS_DOLLAR] = array('first record', 1);
320
321 list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_NAMED], $params[SQL_PARAMS_NAMED]);
322 $this->assertSame($rsql, $sql[$rtype]);
323 $this->assertSame($rparams, $params[$rtype]);
324
325 list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_QM], $params[SQL_PARAMS_QM]);
326 $this->assertSame($rsql, $sql[$rtype]);
327 $this->assertSame($rparams, $params[$rtype]);
328
329 list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_DOLLAR], $params[SQL_PARAMS_DOLLAR]);
330 $this->assertSame($rsql, $sql[$rtype]);
331 $this->assertSame($rparams, $params[$rtype]);
332
9d6d32b6 333 // Malformed table placeholder.
a3d5830a
PS
334 $sql = "SELECT * FROM [testtable]";
335 $sqlarray = $DB->fix_sql_params($sql);
336 $this->assertSame($sql, $sqlarray[0]);
337
9d6d32b6 338 // Mixed param types (colon and dollar).
a3d5830a
PS
339 $sql = "SELECT * FROM {{$tablename}} WHERE name = :param1, course = \$1";
340 $params = array('param1' => 'record1', 'param2' => 3);
341 try {
342 $DB->fix_sql_params($sql, $params);
343 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
344 } catch (moodle_exception $e) {
345 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
346 }
347
9d6d32b6 348 // Mixed param types (question and dollar).
a3d5830a
PS
349 $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = \$1";
350 $params = array('param1' => 'record2', 'param2' => 5);
351 try {
352 $DB->fix_sql_params($sql, $params);
353 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
354 } catch (moodle_exception $e) {
355 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
356 }
357
9d6d32b6 358 // Too few params in sql.
a3d5830a
PS
359 $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = ?, id = ?";
360 $params = array('record2', 3);
361 try {
362 $DB->fix_sql_params($sql, $params);
363 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
364 } catch (moodle_exception $e) {
365 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
366 }
367
9d6d32b6 368 // Too many params in array: no error, just use what is necessary.
a3d5830a
PS
369 $params[] = 1;
370 $params[] = time();
9d6d32b6
PS
371 $sqlarray = $DB->fix_sql_params($sql, $params);
372 $this->assertInternalType('array', $sqlarray);
373 $this->assertCount(3, $sqlarray[1]);
a3d5830a 374
9d6d32b6 375 // Named params missing from array.
a3d5830a
PS
376 $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
377 $params = array('wrongname' => 'record1', 'course' => 1);
378 try {
379 $DB->fix_sql_params($sql, $params);
380 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
381 } catch (moodle_exception $e) {
382 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
383 }
384
385 // Duplicate named param in query - this is a very important feature!!
9d6d32b6 386 // it helps with debugging of sloppy code.
a3d5830a
PS
387 $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :name";
388 $params = array('name' => 'record2', 'course' => 3);
389 try {
390 $DB->fix_sql_params($sql, $params);
391 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
392 } catch (moodle_exception $e) {
393 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
394 }
395
9d6d32b6 396 // Extra named param is ignored.
a3d5830a
PS
397 $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
398 $params = array('name' => 'record1', 'course' => 1, 'extrastuff'=>'haha');
9d6d32b6
PS
399 $sqlarray = $DB->fix_sql_params($sql, $params);
400 $this->assertInternalType('array', $sqlarray);
401 $this->assertCount(2, $sqlarray[1]);
a3d5830a 402
9d6d32b6 403 // Params exceeding 30 chars length.
a3d5830a
PS
404 $sql = "SELECT * FROM {{$tablename}} WHERE name = :long_placeholder_with_more_than_30";
405 $params = array('long_placeholder_with_more_than_30' => 'record1');
406 try {
407 $DB->fix_sql_params($sql, $params);
408 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
409 } catch (moodle_exception $e) {
410 $this->assertInstanceOf('coding_exception', $e);
a3d5830a
PS
411 }
412
9d6d32b6 413 // Booleans in NAMED params are casting to 1/0 int.
a3d5830a
PS
414 $sql = "SELECT * FROM {{$tablename}} WHERE course = ? OR course = ?";
415 $params = array(true, false);
416 list($sql, $params) = $DB->fix_sql_params($sql, $params);
417 $this->assertTrue(reset($params) === 1);
418 $this->assertTrue(next($params) === 0);
419
9d6d32b6 420 // Booleans in QM params are casting to 1/0 int.
a3d5830a
PS
421 $sql = "SELECT * FROM {{$tablename}} WHERE course = :course1 OR course = :course2";
422 $params = array('course1' => true, 'course2' => false);
423 list($sql, $params) = $DB->fix_sql_params($sql, $params);
424 $this->assertTrue(reset($params) === 1);
425 $this->assertTrue(next($params) === 0);
426
9d6d32b6 427 // Booleans in DOLLAR params are casting to 1/0 int.
a3d5830a
PS
428 $sql = "SELECT * FROM {{$tablename}} WHERE course = \$1 OR course = \$2";
429 $params = array(true, false);
430 list($sql, $params) = $DB->fix_sql_params($sql, $params);
431 $this->assertTrue(reset($params) === 1);
432 $this->assertTrue(next($params) === 0);
433
9d6d32b6 434 // No data types are touched except bool.
a3d5830a 435 $sql = "SELECT * FROM {{$tablename}} WHERE name IN (?,?,?,?,?,?)";
9d6d32b6 436 $inparams = array('abc', 'ABC', null, '1', 1, 1.4);
a3d5830a
PS
437 list($sql, $params) = $DB->fix_sql_params($sql, $inparams);
438 $this->assertSame(array_values($params), array_values($inparams));
439 }
440
441 public function test_strtok() {
9d6d32b6 442 // Strtok was previously used by bound emulation, make sure it is not used any more.
a3d5830a
PS
443 $DB = $this->tdb;
444 $dbman = $this->tdb->get_manager();
445
446 $table = $this->get_test_table();
447 $tablename = $table->getName();
448
9d6d32b6
PS
449 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
450 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
451 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
452 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
453 $dbman->create_table($table);
454
455 $str = 'a?b?c?d';
456 $this->assertSame(strtok($str, '?'), 'a');
457
458 $DB->get_records($tablename, array('id'=>1));
459
460 $this->assertSame(strtok('?'), 'b');
461 }
462
463 public function test_tweak_param_names() {
464 // Note the tweak_param_names() method is only available in the oracle driver,
9d6d32b6 465 // hence we look for expected results indirectly, by testing various DML methods.
a3d5830a
PS
466 // with some "extreme" conditions causing the tweak to happen.
467 $DB = $this->tdb;
468 $dbman = $this->tdb->get_manager();
469
470 $table = $this->get_test_table();
471 $tablename = $table->getName();
472
9d6d32b6
PS
473 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
474 // Add some columns with 28 chars in the name.
a3d5830a
PS
475 $table->add_field('long_int_columnname_with_28c', XMLDB_TYPE_INTEGER, '10');
476 $table->add_field('long_dec_columnname_with_28c', XMLDB_TYPE_NUMBER, '10,2');
477 $table->add_field('long_str_columnname_with_28c', XMLDB_TYPE_CHAR, '100');
9d6d32b6 478 // Add some columns with 30 chars in the name.
a3d5830a
PS
479 $table->add_field('long_int_columnname_with_30cxx', XMLDB_TYPE_INTEGER, '10');
480 $table->add_field('long_dec_columnname_with_30cxx', XMLDB_TYPE_NUMBER, '10,2');
481 $table->add_field('long_str_columnname_with_30cxx', XMLDB_TYPE_CHAR, '100');
482
483 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
484
485 $dbman->create_table($table);
486
487 $this->assertTrue($dbman->table_exists($tablename));
488
9d6d32b6 489 // Test insert record.
a3d5830a
PS
490 $rec1 = new stdClass();
491 $rec1->long_int_columnname_with_28c = 28;
492 $rec1->long_dec_columnname_with_28c = 28.28;
493 $rec1->long_str_columnname_with_28c = '28';
494 $rec1->long_int_columnname_with_30cxx = 30;
495 $rec1->long_dec_columnname_with_30cxx = 30.30;
496 $rec1->long_str_columnname_with_30cxx = '30';
497
9d6d32b6 498 // Insert_record().
a3d5830a
PS
499 $rec1->id = $DB->insert_record($tablename, $rec1);
500 $this->assertEquals($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
501
9d6d32b6 502 // Update_record().
a3d5830a
PS
503 $DB->update_record($tablename, $rec1);
504 $this->assertEquals($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
505
9d6d32b6 506 // Set_field().
a3d5830a
PS
507 $rec1->long_int_columnname_with_28c = 280;
508 $DB->set_field($tablename, 'long_int_columnname_with_28c', $rec1->long_int_columnname_with_28c,
509 array('id' => $rec1->id, 'long_int_columnname_with_28c' => 28));
510 $rec1->long_dec_columnname_with_28c = 280.28;
511 $DB->set_field($tablename, 'long_dec_columnname_with_28c', $rec1->long_dec_columnname_with_28c,
512 array('id' => $rec1->id, 'long_dec_columnname_with_28c' => 28.28));
513 $rec1->long_str_columnname_with_28c = '280';
514 $DB->set_field($tablename, 'long_str_columnname_with_28c', $rec1->long_str_columnname_with_28c,
515 array('id' => $rec1->id, 'long_str_columnname_with_28c' => '28'));
516 $rec1->long_int_columnname_with_30cxx = 300;
517 $DB->set_field($tablename, 'long_int_columnname_with_30cxx', $rec1->long_int_columnname_with_30cxx,
518 array('id' => $rec1->id, 'long_int_columnname_with_30cxx' => 30));
519 $rec1->long_dec_columnname_with_30cxx = 300.30;
520 $DB->set_field($tablename, 'long_dec_columnname_with_30cxx', $rec1->long_dec_columnname_with_30cxx,
521 array('id' => $rec1->id, 'long_dec_columnname_with_30cxx' => 30.30));
522 $rec1->long_str_columnname_with_30cxx = '300';
523 $DB->set_field($tablename, 'long_str_columnname_with_30cxx', $rec1->long_str_columnname_with_30cxx,
524 array('id' => $rec1->id, 'long_str_columnname_with_30cxx' => '30'));
525 $this->assertEquals($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
526
9d6d32b6 527 // Delete_records().
a3d5830a
PS
528 $rec2 = $DB->get_record($tablename, array('id' => $rec1->id));
529 $rec2->id = $DB->insert_record($tablename, $rec2);
530 $this->assertEquals(2, $DB->count_records($tablename));
531 $DB->delete_records($tablename, (array) $rec2);
532 $this->assertEquals(1, $DB->count_records($tablename));
533
9d6d32b6 534 // Get_recordset().
a3d5830a
PS
535 $rs = $DB->get_recordset($tablename, (array) $rec1);
536 $iterations = 0;
537 foreach ($rs as $rec2) {
538 $iterations++;
539 }
540 $rs->close();
541 $this->assertEquals(1, $iterations);
542 $this->assertEquals($rec1, $rec2);
543
9d6d32b6 544 // Get_records().
a3d5830a 545 $recs = $DB->get_records($tablename, (array) $rec1);
9d6d32b6 546 $this->assertCount(1, $recs);
a3d5830a
PS
547 $this->assertEquals($rec1, reset($recs));
548
9d6d32b6 549 // Get_fieldset_select().
a3d5830a
PS
550 $select = 'id = :id AND
551 long_int_columnname_with_28c = :long_int_columnname_with_28c AND
552 long_dec_columnname_with_28c = :long_dec_columnname_with_28c AND
553 long_str_columnname_with_28c = :long_str_columnname_with_28c AND
554 long_int_columnname_with_30cxx = :long_int_columnname_with_30cxx AND
555 long_dec_columnname_with_30cxx = :long_dec_columnname_with_30cxx AND
556 long_str_columnname_with_30cxx = :long_str_columnname_with_30cxx';
557 $fields = $DB->get_fieldset_select($tablename, 'long_int_columnname_with_28c', $select, (array)$rec1);
9d6d32b6 558 $this->assertCount(1, $fields);
a3d5830a
PS
559 $this->assertEquals($rec1->long_int_columnname_with_28c, reset($fields));
560 $fields = $DB->get_fieldset_select($tablename, 'long_dec_columnname_with_28c', $select, (array)$rec1);
561 $this->assertEquals($rec1->long_dec_columnname_with_28c, reset($fields));
562 $fields = $DB->get_fieldset_select($tablename, 'long_str_columnname_with_28c', $select, (array)$rec1);
563 $this->assertEquals($rec1->long_str_columnname_with_28c, reset($fields));
564 $fields = $DB->get_fieldset_select($tablename, 'long_int_columnname_with_30cxx', $select, (array)$rec1);
565 $this->assertEquals($rec1->long_int_columnname_with_30cxx, reset($fields));
566 $fields = $DB->get_fieldset_select($tablename, 'long_dec_columnname_with_30cxx', $select, (array)$rec1);
567 $this->assertEquals($rec1->long_dec_columnname_with_30cxx, reset($fields));
568 $fields = $DB->get_fieldset_select($tablename, 'long_str_columnname_with_30cxx', $select, (array)$rec1);
569 $this->assertEquals($rec1->long_str_columnname_with_30cxx, reset($fields));
570
9d6d32b6 571 // Overlapping placeholders (progressive str_replace).
a3d5830a
PS
572 $overlapselect = 'id = :p AND
573 long_int_columnname_with_28c = :param1 AND
574 long_dec_columnname_with_28c = :param2 AND
575 long_str_columnname_with_28c = :param_with_29_characters_long AND
576 long_int_columnname_with_30cxx = :param_with_30_characters_long_ AND
577 long_dec_columnname_with_30cxx = :param_ AND
578 long_str_columnname_with_30cxx = :param__';
579 $overlapparams = array(
580 'p' => $rec1->id,
581 'param1' => $rec1->long_int_columnname_with_28c,
582 'param2' => $rec1->long_dec_columnname_with_28c,
583 'param_with_29_characters_long' => $rec1->long_str_columnname_with_28c,
584 'param_with_30_characters_long_' => $rec1->long_int_columnname_with_30cxx,
585 'param_' => $rec1->long_dec_columnname_with_30cxx,
586 'param__' => $rec1->long_str_columnname_with_30cxx);
587 $recs = $DB->get_records_select($tablename, $overlapselect, $overlapparams);
9d6d32b6 588 $this->assertCount(1, $recs);
a3d5830a
PS
589 $this->assertEquals($rec1, reset($recs));
590
9d6d32b6 591 // Execute().
a3d5830a
PS
592 $DB->execute("DELETE FROM {{$tablename}} WHERE $select", (array)$rec1);
593 $this->assertEquals(0, $DB->count_records($tablename));
594 }
595
596 public function test_get_tables() {
597 $DB = $this->tdb;
598 $dbman = $this->tdb->get_manager();
599
9d6d32b6 600 // Need to test with multiple DBs.
a3d5830a
PS
601 $table = $this->get_test_table();
602 $tablename = $table->getName();
603
604 $original_count = count($DB->get_tables());
605
9d6d32b6 606 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
a3d5830a
PS
607 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
608
609 $dbman->create_table($table);
610 $this->assertTrue(count($DB->get_tables()) == $original_count + 1);
611
612 $dbman->drop_table($table);
613 $this->assertTrue(count($DB->get_tables()) == $original_count);
614 }
615
616 public function test_get_indexes() {
617 $DB = $this->tdb;
618 $dbman = $this->tdb->get_manager();
619
620 $table = $this->get_test_table();
621 $tablename = $table->getName();
622
9d6d32b6
PS
623 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
624 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
625 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
626 $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
627 $table->add_index('course-id', XMLDB_INDEX_UNIQUE, array('course', 'id'));
628 $dbman->create_table($table);
629
630 $indices = $DB->get_indexes($tablename);
9d6d32b6
PS
631 $this->assertInternalType('array', $indices);
632 $this->assertCount(2, $indices);
633 // We do not care about index names for now.
a3d5830a
PS
634 $first = array_shift($indices);
635 $second = array_shift($indices);
636 if (count($first['columns']) == 2) {
637 $composed = $first;
638 $single = $second;
639 } else {
640 $composed = $second;
641 $single = $first;
642 }
643 $this->assertFalse($single['unique']);
644 $this->assertTrue($composed['unique']);
9d6d32b6
PS
645 $this->assertCount(1, $single['columns']);
646 $this->assertCount(2, $composed['columns']);
647 $this->assertSame('course', $single['columns'][0]);
648 $this->assertSame('course', $composed['columns'][0]);
649 $this->assertSame('id', $composed['columns'][1]);
a3d5830a
PS
650 }
651
652 public function test_get_columns() {
653 $DB = $this->tdb;
654 $dbman = $this->tdb->get_manager();
655
656 $table = $this->get_test_table();
657 $tablename = $table->getName();
658
9d6d32b6
PS
659 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
660 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
661 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
662 $table->add_field('description', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
663 $table->add_field('enumfield', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'test2');
664 $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
665 $table->add_field('onefloat', XMLDB_TYPE_FLOAT, '10,2', null, null, null, 300);
666 $table->add_field('anotherfloat', XMLDB_TYPE_FLOAT, null, null, null, null, 400);
667 $table->add_field('negativedfltint', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '-1');
668 $table->add_field('negativedfltnumber', XMLDB_TYPE_NUMBER, '10', null, XMLDB_NOTNULL, null, '-2');
669 $table->add_field('negativedfltfloat', XMLDB_TYPE_FLOAT, '10', null, XMLDB_NOTNULL, null, '-3');
bc5a5527
PS
670 $table->add_field('someint1', XMLDB_TYPE_INTEGER, '1', null, null, null, '0');
671 $table->add_field('someint2', XMLDB_TYPE_INTEGER, '2', null, null, null, '0');
672 $table->add_field('someint3', XMLDB_TYPE_INTEGER, '3', null, null, null, '0');
673 $table->add_field('someint4', XMLDB_TYPE_INTEGER, '4', null, null, null, '0');
674 $table->add_field('someint5', XMLDB_TYPE_INTEGER, '5', null, null, null, '0');
675 $table->add_field('someint6', XMLDB_TYPE_INTEGER, '6', null, null, null, '0');
676 $table->add_field('someint7', XMLDB_TYPE_INTEGER, '7', null, null, null, '0');
677 $table->add_field('someint8', XMLDB_TYPE_INTEGER, '8', null, null, null, '0');
678 $table->add_field('someint9', XMLDB_TYPE_INTEGER, '9', null, null, null, '0');
679 $table->add_field('someint10', XMLDB_TYPE_INTEGER, '10', null, null, null, '0');
680 $table->add_field('someint18', XMLDB_TYPE_INTEGER, '18', null, null, null, '0');
a3d5830a
PS
681 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
682 $dbman->create_table($table);
683
684 $columns = $DB->get_columns($tablename);
9d6d32b6 685 $this->assertInternalType('array', $columns);
a3d5830a
PS
686
687 $fields = $table->getFields();
9d6d32b6 688 $this->assertCount(count($columns), $fields);
a3d5830a
PS
689
690 $field = $columns['id'];
9d6d32b6 691 $this->assertSame('R', $field->meta_type);
a3d5830a
PS
692 $this->assertTrue($field->auto_increment);
693 $this->assertTrue($field->unique);
694
695 $field = $columns['course'];
9d6d32b6 696 $this->assertSame('I', $field->meta_type);
a3d5830a
PS
697 $this->assertFalse($field->auto_increment);
698 $this->assertTrue($field->has_default);
699 $this->assertEquals(0, $field->default_value);
700 $this->assertTrue($field->not_null);
701
9d6d32b6 702 for ($i=1; $i<=10; $i++) {
bc5a5527 703 $field = $columns['someint'.$i];
9d6d32b6 704 $this->assertSame('I', $field->meta_type);
bc5a5527
PS
705 $this->assertGreaterThanOrEqual($i, $field->max_length);
706 }
707 $field = $columns['someint18'];
9d6d32b6 708 $this->assertSame('I', $field->meta_type);
bc5a5527
PS
709 $this->assertGreaterThanOrEqual(18, $field->max_length);
710
a3d5830a 711 $field = $columns['name'];
9d6d32b6 712 $this->assertSame('C', $field->meta_type);
a3d5830a
PS
713 $this->assertFalse($field->auto_increment);
714 $this->assertEquals(255, $field->max_length);
715 $this->assertTrue($field->has_default);
716 $this->assertSame('lala', $field->default_value);
717 $this->assertFalse($field->not_null);
718
719 $field = $columns['description'];
9d6d32b6 720 $this->assertSame('X', $field->meta_type);
a3d5830a
PS
721 $this->assertFalse($field->auto_increment);
722 $this->assertFalse($field->has_default);
9d6d32b6 723 $this->assertNull($field->default_value);
a3d5830a
PS
724 $this->assertFalse($field->not_null);
725
726 $field = $columns['enumfield'];
9d6d32b6 727 $this->assertSame('C', $field->meta_type);
a3d5830a
PS
728 $this->assertFalse($field->auto_increment);
729 $this->assertSame('test2', $field->default_value);
730 $this->assertTrue($field->not_null);
731
732 $field = $columns['onenum'];
9d6d32b6 733 $this->assertSame('N', $field->meta_type);
a3d5830a
PS
734 $this->assertFalse($field->auto_increment);
735 $this->assertEquals(10, $field->max_length);
736 $this->assertEquals(2, $field->scale);
737 $this->assertTrue($field->has_default);
738 $this->assertEquals(200.0, $field->default_value);
739 $this->assertFalse($field->not_null);
740
741 $field = $columns['onefloat'];
9d6d32b6 742 $this->assertSame('N', $field->meta_type);
a3d5830a
PS
743 $this->assertFalse($field->auto_increment);
744 $this->assertTrue($field->has_default);
745 $this->assertEquals(300.0, $field->default_value);
746 $this->assertFalse($field->not_null);
747
748 $field = $columns['anotherfloat'];
9d6d32b6 749 $this->assertSame('N', $field->meta_type);
a3d5830a
PS
750 $this->assertFalse($field->auto_increment);
751 $this->assertTrue($field->has_default);
752 $this->assertEquals(400.0, $field->default_value);
753 $this->assertFalse($field->not_null);
754
9d6d32b6 755 // Test negative defaults in numerical columns.
a3d5830a
PS
756 $field = $columns['negativedfltint'];
757 $this->assertTrue($field->has_default);
758 $this->assertEquals(-1, $field->default_value);
759
760 $field = $columns['negativedfltnumber'];
761 $this->assertTrue($field->has_default);
762 $this->assertEquals(-2, $field->default_value);
763
764 $field = $columns['negativedfltfloat'];
765 $this->assertTrue($field->has_default);
766 $this->assertEquals(-3, $field->default_value);
767
768 for ($i = 0; $i < count($columns); $i++) {
769 if ($i == 0) {
770 $next_column = reset($columns);
771 $next_field = reset($fields);
772 } else {
773 $next_column = next($columns);
774 $next_field = next($fields);
775 }
776
94417438 777 $this->assertEquals($next_column->name, $next_field->getName());
a3d5830a
PS
778 }
779
9d6d32b6 780 // Test get_columns for non-existing table returns empty array. MDL-30147.
a3d5830a
PS
781 $columns = $DB->get_columns('xxxx');
782 $this->assertEquals(array(), $columns);
4bf85577 783
9d6d32b6 784 // Create something similar to "context_temp" with id column without sequence.
4bf85577
PS
785 $dbman->drop_table($table);
786 $table = $this->get_test_table();
787 $tablename = $table->getName();
9d6d32b6
PS
788 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
789 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
4bf85577
PS
790 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
791 $dbman->create_table($table);
792
793 $columns = $DB->get_columns($tablename);
794 $this->assertFalse($columns['id']->auto_increment);
a3d5830a
PS
795 }
796
797 public function test_get_manager() {
798 $DB = $this->tdb;
799 $dbman = $this->tdb->get_manager();
800
9d6d32b6 801 $this->assertInstanceOf('database_manager', $dbman);
a3d5830a
PS
802 }
803
804 public function test_setup_is_unicodedb() {
805 $DB = $this->tdb;
806 $this->assertTrue($DB->setup_is_unicodedb());
807 }
808
9d6d32b6 809 public function test_set_debug() { // Tests get_debug() too.
a3d5830a
PS
810 $DB = $this->tdb;
811 $dbman = $this->tdb->get_manager();
812
813 $table = $this->get_test_table();
814 $tablename = $table->getName();
815
9d6d32b6
PS
816 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
817 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
818 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
819 $dbman->create_table($table);
820
821 $sql = "SELECT * FROM {{$tablename}}";
822
823 $prevdebug = $DB->get_debug();
824
825 ob_start();
826 $DB->set_debug(true);
827 $this->assertTrue($DB->get_debug());
828 $DB->execute($sql);
829 $DB->set_debug(false);
830 $this->assertFalse($DB->get_debug());
831 $debuginfo = ob_get_contents();
832 ob_end_clean();
833 $this->assertFalse($debuginfo === '');
834
835 ob_start();
836 $DB->execute($sql);
837 $debuginfo = ob_get_contents();
838 ob_end_clean();
839 $this->assertTrue($debuginfo === '');
840
841 $DB->set_debug($prevdebug);
842 }
843
844 public function test_execute() {
845 $DB = $this->tdb;
846 $dbman = $this->tdb->get_manager();
847
848 $table1 = $this->get_test_table('1');
849 $tablename1 = $table1->getName();
9d6d32b6
PS
850 $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
851 $table1->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
852 $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
853 $table1->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
854 $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
855 $dbman->create_table($table1);
856
857 $table2 = $this->get_test_table('2');
858 $tablename2 = $table2->getName();
9d6d32b6
PS
859 $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
860 $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
861 $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
862 $dbman->create_table($table2);
863
864 $DB->insert_record($tablename1, array('course' => 3, 'name' => 'aaa'));
865 $DB->insert_record($tablename1, array('course' => 1, 'name' => 'bbb'));
866 $DB->insert_record($tablename1, array('course' => 7, 'name' => 'ccc'));
867 $DB->insert_record($tablename1, array('course' => 3, 'name' => 'ddd'));
868
9d6d32b6 869 // Select results are ignored.
a3d5830a
PS
870 $sql = "SELECT * FROM {{$tablename1}} WHERE course = :course";
871 $this->assertTrue($DB->execute($sql, array('course'=>3)));
872
9d6d32b6 873 // Throw exception on error.
a3d5830a
PS
874 $sql = "XXUPDATE SET XSSD";
875 try {
876 $DB->execute($sql);
877 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
878 } catch (moodle_exception $e) {
879 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
880 }
881
9d6d32b6 882 // Update records.
a3d5830a
PS
883 $sql = "UPDATE {{$tablename1}}
884 SET course = 6
885 WHERE course = ?";
886 $this->assertTrue($DB->execute($sql, array('3')));
9d6d32b6 887 $this->assertEquals(2, $DB->count_records($tablename1, array('course' => 6)));
a3d5830a 888
9d6d32b6
PS
889 // Update records with subquery condition.
890 // Confirm that the option not using table aliases is cross-db.
a3d5830a
PS
891 $sql = "UPDATE {{$tablename1}}
892 SET course = 0
893 WHERE NOT EXISTS (
894 SELECT course
895 FROM {{$tablename2}} tbl2
896 WHERE tbl2.course = {{$tablename1}}.course
9d6d32b6 897 AND 1 = 0)"; // Really we don't update anything, but verify the syntax is allowed.
a3d5830a
PS
898 $this->assertTrue($DB->execute($sql));
899
9d6d32b6 900 // Insert from one into second table.
a3d5830a
PS
901 $sql = "INSERT INTO {{$tablename2}} (course)
902
903 SELECT course
904 FROM {{$tablename1}}";
905 $this->assertTrue($DB->execute($sql));
9d6d32b6 906 $this->assertEquals(4, $DB->count_records($tablename2));
a3d5830a
PS
907 }
908
909 public function test_get_recordset() {
910 $DB = $this->tdb;
911 $dbman = $DB->get_manager();
912
913 $table = $this->get_test_table();
914 $tablename = $table->getName();
915
9d6d32b6
PS
916 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
917 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
918 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
919 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
920 $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
921 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
922 $dbman->create_table($table);
923
401793a3
924 $data = array(array('course' => 3, 'name' => 'record1', 'onetext'=>'abc'),
925 array('course' => 3, 'name' => 'record2', 'onetext'=>'abcd'),
926 array('course' => 5, 'name' => 'record3', 'onetext'=>'abcde'));
a3d5830a 927
9d6d32b6 928 foreach ($data as $key => $record) {
401793a3 929 $data[$key]['id'] = $DB->insert_record($tablename, $record);
a3d5830a
PS
930 }
931
9d6d32b6 932 // Standard recordset iteration.
a3d5830a 933 $rs = $DB->get_recordset($tablename);
9d6d32b6 934 $this->assertInstanceOf('moodle_recordset', $rs);
a3d5830a 935 reset($data);
9d6d32b6 936 foreach ($rs as $record) {
a3d5830a
PS
937 $data_record = current($data);
938 foreach ($record as $k => $v) {
939 $this->assertEquals($data_record[$k], $v);
940 }
941 next($data);
942 }
943 $rs->close();
944
9d6d32b6 945 // Iterator style usage.
a3d5830a 946 $rs = $DB->get_recordset($tablename);
9d6d32b6 947 $this->assertInstanceOf('moodle_recordset', $rs);
a3d5830a
PS
948 reset($data);
949 while ($rs->valid()) {
950 $record = $rs->current();
951 $data_record = current($data);
952 foreach ($record as $k => $v) {
953 $this->assertEquals($data_record[$k], $v);
954 }
955 next($data);
956 $rs->next();
957 }
958 $rs->close();
959
9d6d32b6 960 // Make sure rewind is ignored.
a3d5830a 961 $rs = $DB->get_recordset($tablename);
9d6d32b6 962 $this->assertInstanceOf('moodle_recordset', $rs);
a3d5830a
PS
963 reset($data);
964 $i = 0;
9d6d32b6 965 foreach ($rs as $record) {
a3d5830a
PS
966 $i++;
967 $rs->rewind();
968 if ($i > 10) {
969 $this->fail('revind not ignored in recordsets');
970 break;
971 }
972 $data_record = current($data);
973 foreach ($record as $k => $v) {
974 $this->assertEquals($data_record[$k], $v);
975 }
976 next($data);
977 }
978 $rs->close();
979
9d6d32b6 980 // Test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int).
a3d5830a
PS
981 $conditions = array('onetext' => '1');
982 try {
983 $rs = $DB->get_recordset($tablename, $conditions);
eb10d554 984 $this->fail('An Exception is missing, expected due to equating of text fields');
9d6d32b6
PS
985 } catch (moodle_exception $e) {
986 $this->assertInstanceOf('dml_exception', $e);
987 $this->assertSame('textconditionsnotallowed', $e->errorcode);
a3d5830a
PS
988 }
989
541ca062
990 // Test nested iteration.
991 $rs1 = $DB->get_recordset($tablename);
992 $i = 0;
9d6d32b6 993 foreach ($rs1 as $record1) {
541ca062
994 $rs2 = $DB->get_recordset($tablename);
995 $i++;
996 $j = 0;
9d6d32b6 997 foreach ($rs2 as $record2) {
541ca062
998 $j++;
999 }
1000 $rs2->close();
9d6d32b6 1001 $this->assertCount($j, $data);
541ca062
1002 }
1003 $rs1->close();
9d6d32b6 1004 $this->assertCount($i, $data);
541ca062 1005
9d6d32b6 1006 // Notes:
a3d5830a
PS
1007 // * limits are tested in test_get_recordset_sql()
1008 // * where_clause() is used internally and is tested in test_get_records()
1009 }
1010
3b5f6e6c
1011 public function test_get_recordset_static() {
1012 $DB = $this->tdb;
1013 $dbman = $DB->get_manager();
1014
1015 $table = $this->get_test_table();
1016 $tablename = $table->getName();
1017
9d6d32b6
PS
1018 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1019 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
3b5f6e6c
1020 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1021 $dbman->create_table($table);
1022
1023 $DB->insert_record($tablename, array('course' => 1));
1024 $DB->insert_record($tablename, array('course' => 2));
1025 $DB->insert_record($tablename, array('course' => 3));
1026 $DB->insert_record($tablename, array('course' => 4));
1027
1028 $rs = $DB->get_recordset($tablename, array(), 'id');
1029
1030 $DB->set_field($tablename, 'course', 666, array('course'=>1));
1031 $DB->delete_records($tablename, array('course'=>2));
1032
1033 $i = 0;
9d6d32b6 1034 foreach ($rs as $record) {
3b5f6e6c
1035 $i++;
1036 $this->assertEquals($i, $record->course);
1037 }
1038 $rs->close();
1039 $this->assertEquals(4, $i);
1040
1041 // Now repeat with limits because it may use different code.
1042 $DB->delete_records($tablename, array());
1043
1044 $DB->insert_record($tablename, array('course' => 1));
1045 $DB->insert_record($tablename, array('course' => 2));
1046 $DB->insert_record($tablename, array('course' => 3));
1047 $DB->insert_record($tablename, array('course' => 4));
1048
1049 $rs = $DB->get_recordset($tablename, array(), 'id', '*', 0, 3);
1050
1051 $DB->set_field($tablename, 'course', 666, array('course'=>1));
1052 $DB->delete_records($tablename, array('course'=>2));
1053
1054 $i = 0;
9d6d32b6 1055 foreach ($rs as $record) {
3b5f6e6c
1056 $i++;
1057 $this->assertEquals($i, $record->course);
1058 }
1059 $rs->close();
1060 $this->assertEquals(3, $i);
1061 }
1062
a3d5830a
PS
1063 public function test_get_recordset_iterator_keys() {
1064 $DB = $this->tdb;
1065 $dbman = $DB->get_manager();
1066
1067 $table = $this->get_test_table();
1068 $tablename = $table->getName();
1069
9d6d32b6
PS
1070 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1071 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1072 $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
1073 $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
1074 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1075 $dbman->create_table($table);
1076
401793a3
1077 $data = array(array('course' => 3, 'name' => 'record1'),
1078 array('course' => 3, 'name' => 'record2'),
1079 array('course' => 5, 'name' => 'record3'));
9d6d32b6 1080 foreach ($data as $key => $record) {
401793a3 1081 $data[$key]['id'] = $DB->insert_record($tablename, $record);
a3d5830a
PS
1082 }
1083
9d6d32b6
PS
1084 // Test repeated numeric keys are returned ok.
1085 $rs = $DB->get_recordset($tablename, null, null, 'course, name, id');
a3d5830a
PS
1086
1087 reset($data);
1088 $count = 0;
9d6d32b6 1089 foreach ($rs as $key => $record) {
a3d5830a
PS
1090 $data_record = current($data);
1091 $this->assertEquals($data_record['course'], $key);
1092 next($data);
1093 $count++;
1094 }
1095 $rs->close();
9d6d32b6 1096 $this->assertEquals(3, $count);
a3d5830a 1097
9d6d32b6
PS
1098 // Test string keys are returned ok.
1099 $rs = $DB->get_recordset($tablename, null, null, 'name, course, id');
a3d5830a
PS
1100
1101 reset($data);
1102 $count = 0;
9d6d32b6 1103 foreach ($rs as $key => $record) {
a3d5830a
PS
1104 $data_record = current($data);
1105 $this->assertEquals($data_record['name'], $key);
1106 next($data);
1107 $count++;
1108 }
1109 $rs->close();
9d6d32b6 1110 $this->assertEquals(3, $count);
a3d5830a 1111
9d6d32b6
PS
1112 // Test numeric not starting in 1 keys are returned ok.
1113 $rs = $DB->get_recordset($tablename, null, 'id DESC', 'id, course, name');
a3d5830a
PS
1114
1115 $data = array_reverse($data);
1116 reset($data);
1117 $count = 0;
9d6d32b6 1118 foreach ($rs as $key => $record) {
a3d5830a
PS
1119 $data_record = current($data);
1120 $this->assertEquals($data_record['id'], $key);
1121 next($data);
1122 $count++;
1123 }
1124 $rs->close();
9d6d32b6 1125 $this->assertEquals(3, $count);
a3d5830a
PS
1126 }
1127
1128 public function test_get_recordset_list() {
1129 $DB = $this->tdb;
1130 $dbman = $DB->get_manager();
1131
1132 $table = $this->get_test_table();
1133 $tablename = $table->getName();
1134
9d6d32b6
PS
1135 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1136 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, null, null, '0');
a3d5830a
PS
1137 $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
1138 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1139 $dbman->create_table($table);
1140
1141 $DB->insert_record($tablename, array('course' => 3));
1142 $DB->insert_record($tablename, array('course' => 3));
1143 $DB->insert_record($tablename, array('course' => 5));
1144 $DB->insert_record($tablename, array('course' => 2));
7f22fb4d
1145 $DB->insert_record($tablename, array('course' => null));
1146 $DB->insert_record($tablename, array('course' => 1));
1147 $DB->insert_record($tablename, array('course' => 0));
a3d5830a
PS
1148
1149 $rs = $DB->get_recordset_list($tablename, 'course', array(3, 2));
a3d5830a
PS
1150 $counter = 0;
1151 foreach ($rs as $record) {
1152 $counter++;
1153 }
1154 $this->assertEquals(3, $counter);
1155 $rs->close();
1156
7f22fb4d
1157 $rs = $DB->get_recordset_list($tablename, 'course', array(3));
1158 $counter = 0;
1159 foreach ($rs as $record) {
1160 $counter++;
1161 }
1162 $this->assertEquals(2, $counter);
1163 $rs->close();
1164
1165 $rs = $DB->get_recordset_list($tablename, 'course', array(null));
1166 $counter = 0;
1167 foreach ($rs as $record) {
1168 $counter++;
1169 }
1170 $this->assertEquals(1, $counter);
1171 $rs->close();
1172
1173 $rs = $DB->get_recordset_list($tablename, 'course', array(6, null));
1174 $counter = 0;
1175 foreach ($rs as $record) {
1176 $counter++;
1177 }
1178 $this->assertEquals(1, $counter);
1179 $rs->close();
1180
1181 $rs = $DB->get_recordset_list($tablename, 'course', array(null, 5, 5, 5));
1182 $counter = 0;
1183 foreach ($rs as $record) {
1184 $counter++;
1185 }
1186 $this->assertEquals(2, $counter);
1187 $rs->close();
1188
1189 $rs = $DB->get_recordset_list($tablename, 'course', array(true));
1190 $counter = 0;
1191 foreach ($rs as $record) {
1192 $counter++;
1193 }
1194 $this->assertEquals(1, $counter);
1195 $rs->close();
1196
1197 $rs = $DB->get_recordset_list($tablename, 'course', array(false));
1198 $counter = 0;
1199 foreach ($rs as $record) {
1200 $counter++;
1201 }
1202 $this->assertEquals(1, $counter);
1203 $rs->close();
1204
9d6d32b6 1205 $rs = $DB->get_recordset_list($tablename, 'course', array()); // Must return 0 rows without conditions. MDL-17645.
a3d5830a
PS
1206
1207 $counter = 0;
1208 foreach ($rs as $record) {
1209 $counter++;
1210 }
1211 $rs->close();
1212 $this->assertEquals(0, $counter);
1213
9d6d32b6 1214 // Notes:
a3d5830a
PS
1215 // * limits are tested in test_get_recordset_sql()
1216 // * where_clause() is used internally and is tested in test_get_records()
1217 }
1218
1219 public function test_get_recordset_select() {
1220 $DB = $this->tdb;
1221 $dbman = $DB->get_manager();
1222
1223 $table = $this->get_test_table();
1224 $tablename = $table->getName();
1225
9d6d32b6
PS
1226 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1227 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1228 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1229 $dbman->create_table($table);
1230
1231 $DB->insert_record($tablename, array('course' => 3));
1232 $DB->insert_record($tablename, array('course' => 3));
1233 $DB->insert_record($tablename, array('course' => 5));
1234 $DB->insert_record($tablename, array('course' => 2));
1235
1236 $rs = $DB->get_recordset_select($tablename, '');
1237 $counter = 0;
1238 foreach ($rs as $record) {
1239 $counter++;
1240 }
1241 $rs->close();
1242 $this->assertEquals(4, $counter);
1243
1244 $this->assertNotEmpty($rs = $DB->get_recordset_select($tablename, 'course = 3'));
1245 $counter = 0;
1246 foreach ($rs as $record) {
1247 $counter++;
1248 }
1249 $rs->close();
1250 $this->assertEquals(2, $counter);
1251
9d6d32b6 1252 // Notes:
a3d5830a
PS
1253 // * limits are tested in test_get_recordset_sql()
1254 }
1255
1256 public function test_get_recordset_sql() {
1257 $DB = $this->tdb;
1258 $dbman = $DB->get_manager();
1259
1260 $table = $this->get_test_table();
1261 $tablename = $table->getName();
1262
9d6d32b6
PS
1263 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1264 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1265 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1266 $dbman->create_table($table);
1267
1268 $inskey1 = $DB->insert_record($tablename, array('course' => 3));
1269 $inskey2 = $DB->insert_record($tablename, array('course' => 5));
1270 $inskey3 = $DB->insert_record($tablename, array('course' => 4));
1271 $inskey4 = $DB->insert_record($tablename, array('course' => 3));
1272 $inskey5 = $DB->insert_record($tablename, array('course' => 2));
1273 $inskey6 = $DB->insert_record($tablename, array('course' => 1));
1274 $inskey7 = $DB->insert_record($tablename, array('course' => 0));
1275
1276 $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
1277 $counter = 0;
1278 foreach ($rs as $record) {
1279 $counter++;
1280 }
1281 $rs->close();
1282 $this->assertEquals(2, $counter);
1283
9d6d32b6
PS
1284 // Limits - only need to test this case, the rest have been tested by test_get_records_sql()
1285 // only limitfrom = skips that number of records.
a3d5830a
PS
1286 $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
1287 $records = array();
9d6d32b6 1288 foreach ($rs as $key => $record) {
a3d5830a
PS
1289 $records[$key] = $record;
1290 }
1291 $rs->close();
9d6d32b6 1292 $this->assertCount(5, $records);
a3d5830a
PS
1293 $this->assertEquals($inskey3, reset($records)->id);
1294 $this->assertEquals($inskey7, end($records)->id);
1295
9d6d32b6 1296 // Note: fetching nulls, empties, LOBs already tested by test_insert_record() no needed here.
a3d5830a
PS
1297 }
1298
cabc4112
PS
1299 public function test_export_table_recordset() {
1300 $DB = $this->tdb;
1301 $dbman = $DB->get_manager();
1302
1303 $table = $this->get_test_table();
1304 $tablename = $table->getName();
1305
1306 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1307 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1308 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1309 $dbman->create_table($table);
1310
1311 $ids = array();
1312 $ids[] = $DB->insert_record($tablename, array('course' => 3));
1313 $ids[] = $DB->insert_record($tablename, array('course' => 5));
1314 $ids[] = $DB->insert_record($tablename, array('course' => 4));
1315 $ids[] = $DB->insert_record($tablename, array('course' => 3));
1316 $ids[] = $DB->insert_record($tablename, array('course' => 2));
1317 $ids[] = $DB->insert_record($tablename, array('course' => 1));
1318 $ids[] = $DB->insert_record($tablename, array('course' => 0));
1319
1320 $rs = $DB->export_table_recordset($tablename);
1321 $rids = array();
1322 foreach ($rs as $record) {
1323 $rids[] = $record->id;
1324 }
1325 $rs->close();
1326 $this->assertEquals($ids, $rids, '', 0, 0, true);
1327 }
1328
a3d5830a
PS
1329 public function test_get_records() {
1330 $DB = $this->tdb;
1331 $dbman = $DB->get_manager();
1332
1333 $table = $this->get_test_table();
1334 $tablename = $table->getName();
1335
9d6d32b6
PS
1336 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1337 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1338 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1339 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1340 $dbman->create_table($table);
1341
1342 $DB->insert_record($tablename, array('course' => 3));
1343 $DB->insert_record($tablename, array('course' => 3));
1344 $DB->insert_record($tablename, array('course' => 5));
1345 $DB->insert_record($tablename, array('course' => 2));
1346
9d6d32b6 1347 // All records.
a3d5830a 1348 $records = $DB->get_records($tablename);
9d6d32b6 1349 $this->assertCount(4, $records);
a3d5830a
PS
1350 $this->assertEquals(3, $records[1]->course);
1351 $this->assertEquals(3, $records[2]->course);
1352 $this->assertEquals(5, $records[3]->course);
1353 $this->assertEquals(2, $records[4]->course);
1354
9d6d32b6 1355 // Records matching certain conditions.
a3d5830a 1356 $records = $DB->get_records($tablename, array('course' => 3));
9d6d32b6 1357 $this->assertCount(2, $records);
a3d5830a
PS
1358 $this->assertEquals(3, $records[1]->course);
1359 $this->assertEquals(3, $records[2]->course);
1360
9d6d32b6 1361 // All records sorted by course.
a3d5830a 1362 $records = $DB->get_records($tablename, null, 'course');
9d6d32b6 1363 $this->assertCount(4, $records);
a3d5830a
PS
1364 $current_record = reset($records);
1365 $this->assertEquals(4, $current_record->id);
1366 $current_record = next($records);
1367 $this->assertEquals(1, $current_record->id);
1368 $current_record = next($records);
1369 $this->assertEquals(2, $current_record->id);
1370 $current_record = next($records);
1371 $this->assertEquals(3, $current_record->id);
1372
9d6d32b6 1373 // All records, but get only one field.
a3d5830a
PS
1374 $records = $DB->get_records($tablename, null, '', 'id');
1375 $this->assertFalse(isset($records[1]->course));
1376 $this->assertTrue(isset($records[1]->id));
9d6d32b6 1377 $this->assertCount(4, $records);
a3d5830a 1378
9d6d32b6 1379 // Booleans into params.
a3d5830a 1380 $records = $DB->get_records($tablename, array('course' => true));
9d6d32b6 1381 $this->assertCount(0, $records);
a3d5830a 1382 $records = $DB->get_records($tablename, array('course' => false));
9d6d32b6 1383 $this->assertCount(0, $records);
a3d5830a 1384
9d6d32b6 1385 // Test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int).
a3d5830a
PS
1386 $conditions = array('onetext' => '1');
1387 try {
1388 $records = $DB->get_records($tablename, $conditions);
1389 if (debugging()) {
9d6d32b6 1390 // Only in debug mode - hopefully all devs test code in debug mode...
a3d5830a
PS
1391 $this->fail('An Exception is missing, expected due to equating of text fields');
1392 }
9d6d32b6
PS
1393 } catch (moodle_exception $e) {
1394 $this->assertInstanceOf('dml_exception', $e);
1395 $this->assertSame('textconditionsnotallowed', $e->errorcode);
a3d5830a
PS
1396 }
1397
9d6d32b6
PS
1398 // Test get_records passing non-existing table.
1399 // with params.
a3d5830a
PS
1400 try {
1401 $records = $DB->get_records('xxxx', array('id' => 0));
1402 $this->fail('An Exception is missing, expected due to query against non-existing table');
9d6d32b6
PS
1403 } catch (moodle_exception $e) {
1404 $this->assertInstanceOf('dml_exception', $e);
a3d5830a 1405 if (debugging()) {
9d6d32b6
PS
1406 // Information for developers only, normal users get general error message.
1407 $this->assertSame('ddltablenotexist', $e->errorcode);
a3d5830a
PS
1408 }
1409 }
9d6d32b6 1410 // And without params.
a3d5830a
PS
1411 try {
1412 $records = $DB->get_records('xxxx', array());
1413 $this->fail('An Exception is missing, expected due to query against non-existing table');
9d6d32b6
PS
1414 } catch (moodle_exception $e) {
1415 $this->assertInstanceOf('dml_exception', $e);
a3d5830a 1416 if (debugging()) {
9d6d32b6
PS
1417 // Information for developers only, normal users get general error message.
1418 $this->assertSame('ddltablenotexist', $e->errorcode);
a3d5830a
PS
1419 }
1420 }
1421
9d6d32b6 1422 // Test get_records passing non-existing column.
a3d5830a
PS
1423 try {
1424 $records = $DB->get_records($tablename, array('xxxx' => 0));
1425 $this->fail('An Exception is missing, expected due to query against non-existing column');
9d6d32b6
PS
1426 } catch (moodle_exception $e) {
1427 $this->assertInstanceOf('dml_exception', $e);
a3d5830a 1428 if (debugging()) {
9d6d32b6
PS
1429 // Information for developers only, normal users get general error message.
1430 $this->assertSame('ddlfieldnotexist', $e->errorcode);
a3d5830a
PS
1431 }
1432 }
1433
9d6d32b6 1434 // Note: delegate limits testing to test_get_records_sql().
a3d5830a
PS
1435 }
1436
1437 public function test_get_records_list() {
1438 $DB = $this->tdb;
1439 $dbman = $DB->get_manager();
1440
1441 $table = $this->get_test_table();
1442 $tablename = $table->getName();
1443
9d6d32b6
PS
1444 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1445 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1446 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1447 $dbman->create_table($table);
1448
1449 $DB->insert_record($tablename, array('course' => 3));
1450 $DB->insert_record($tablename, array('course' => 3));
1451 $DB->insert_record($tablename, array('course' => 5));
1452 $DB->insert_record($tablename, array('course' => 2));
1453
1454 $records = $DB->get_records_list($tablename, 'course', array(3, 2));
9d6d32b6
PS
1455 $this->assertInternalType('array', $records);
1456 $this->assertCount(3, $records);
a3d5830a
PS
1457 $this->assertEquals(1, reset($records)->id);
1458 $this->assertEquals(2, next($records)->id);
1459 $this->assertEquals(4, next($records)->id);
1460
9d6d32b6
PS
1461 $this->assertSame(array(), $records = $DB->get_records_list($tablename, 'course', array())); // Must return 0 rows without conditions. MDL-17645.
1462 $this->assertCount(0, $records);
a3d5830a 1463
9d6d32b6 1464 // Note: delegate limits testing to test_get_records_sql().
a3d5830a
PS
1465 }
1466
1467 public function test_get_records_sql() {
1468 $DB = $this->tdb;
1469 $dbman = $DB->get_manager();
1470
1471 $table = $this->get_test_table();
1472 $tablename = $table->getName();
1473
9d6d32b6
PS
1474 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1475 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1476 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1477 $dbman->create_table($table);
1478
1479 $inskey1 = $DB->insert_record($tablename, array('course' => 3));
1480 $inskey2 = $DB->insert_record($tablename, array('course' => 5));
1481 $inskey3 = $DB->insert_record($tablename, array('course' => 4));
1482 $inskey4 = $DB->insert_record($tablename, array('course' => 3));
1483 $inskey5 = $DB->insert_record($tablename, array('course' => 2));
1484 $inskey6 = $DB->insert_record($tablename, array('course' => 1));
1485 $inskey7 = $DB->insert_record($tablename, array('course' => 0));
1486
1487 $table2 = $this->get_test_table("2");
1488 $tablename2 = $table2->getName();
9d6d32b6
PS
1489 $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1490 $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1491 $table2->add_field('nametext', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
1492 $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1493 $dbman->create_table($table2);
1494
1495 $DB->insert_record($tablename2, array('course'=>3, 'nametext'=>'badabing'));
1496 $DB->insert_record($tablename2, array('course'=>4, 'nametext'=>'badabang'));
1497 $DB->insert_record($tablename2, array('course'=>5, 'nametext'=>'badabung'));
1498 $DB->insert_record($tablename2, array('course'=>6, 'nametext'=>'badabong'));
1499
1500 $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE course = ?", array(3));
9d6d32b6 1501 $this->assertCount(2, $records);
a3d5830a
PS
1502 $this->assertEquals($inskey1, reset($records)->id);
1503 $this->assertEquals($inskey4, next($records)->id);
1504
9d6d32b6 1505 // Awful test, requires debug enabled and sent to browser. Let's do that and restore after test.
a3d5830a 1506 $records = $DB->get_records_sql("SELECT course AS id, course AS course FROM {{$tablename}}", null);
eb10d554 1507 $this->assertDebuggingCalled();
9d6d32b6 1508 $this->assertCount(6, $records);
96f81ea3 1509 set_debugging(DEBUG_MINIMAL);
eb10d554
PS
1510 $records = $DB->get_records_sql("SELECT course AS id, course AS course FROM {{$tablename}}", null);
1511 $this->assertDebuggingNotCalled();
9d6d32b6 1512 $this->assertCount(6, $records);
96f81ea3 1513 set_debugging(DEBUG_DEVELOPER);
a3d5830a 1514
9d6d32b6 1515 // Negative limits = no limits.
a3d5830a 1516 $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, -1, -1);
9d6d32b6 1517 $this->assertCount(7, $records);
a3d5830a 1518
9d6d32b6 1519 // Zero limits = no limits.
a3d5830a 1520 $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 0);
9d6d32b6 1521 $this->assertCount(7, $records);
a3d5830a 1522
9d6d32b6 1523 // Only limitfrom = skips that number of records.
a3d5830a 1524 $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 2, 0);
9d6d32b6 1525 $this->assertCount(5, $records);
a3d5830a
PS
1526 $this->assertEquals($inskey3, reset($records)->id);
1527 $this->assertEquals($inskey7, end($records)->id);
1528
9d6d32b6 1529 // Only limitnum = fetches that number of records.
a3d5830a 1530 $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 0, 3);
9d6d32b6 1531 $this->assertCount(3, $records);
a3d5830a
PS
1532 $this->assertEquals($inskey1, reset($records)->id);
1533 $this->assertEquals($inskey3, end($records)->id);
1534
9d6d32b6 1535 // Both limitfrom and limitnum = skips limitfrom records and fetches limitnum ones.
a3d5830a 1536 $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} ORDER BY id", null, 3, 2);
9d6d32b6 1537 $this->assertCount(2, $records);
a3d5830a
PS
1538 $this->assertEquals($inskey4, reset($records)->id);
1539 $this->assertEquals($inskey5, end($records)->id);
1540
9d6d32b6
PS
1541 // Both limitfrom and limitnum in query having subqueris.
1542 // Note the subquery skips records with course = 0 and 3.
a3d5830a
PS
1543 $sql = "SELECT * FROM {{$tablename}}
1544 WHERE course NOT IN (
1545 SELECT course FROM {{$tablename}}
1546 WHERE course IN (0, 3))
1547 ORDER BY course";
9d6d32b6
PS
1548 $records = $DB->get_records_sql($sql, null, 0, 2); // Skip 0, get 2.
1549 $this->assertCount(2, $records);
a3d5830a
PS
1550 $this->assertEquals($inskey6, reset($records)->id);
1551 $this->assertEquals($inskey5, end($records)->id);
9d6d32b6
PS
1552 $records = $DB->get_records_sql($sql, null, 2, 2); // Skip 2, get 2.
1553 $this->assertCount(2, $records);
a3d5830a
PS
1554 $this->assertEquals($inskey3, reset($records)->id);
1555 $this->assertEquals($inskey2, end($records)->id);
1556
9d6d32b6 1557 // Test 2 tables with aliases and limits with order bys.
a3d5830a
PS
1558 $sql = "SELECT t1.id, t1.course AS cid, t2.nametext
1559 FROM {{$tablename}} t1, {{$tablename2}} t2
1560 WHERE t2.course=t1.course
1561 ORDER BY t1.course, ". $DB->sql_compare_text('t2.nametext');
9d6d32b6
PS
1562 $records = $DB->get_records_sql($sql, null, 2, 2); // Skip courses 3 and 6, get 4 and 5.
1563 $this->assertCount(2, $records);
1564 $this->assertSame('5', end($records)->cid);
1565 $this->assertSame('4', reset($records)->cid);
a3d5830a 1566
9d6d32b6
PS
1567 // Test 2 tables with aliases and limits with the highest INT limit works.
1568 $records = $DB->get_records_sql($sql, null, 2, PHP_INT_MAX); // Skip course {3,6}, get {4,5}.
1569 $this->assertCount(2, $records);
1570 $this->assertSame('5', end($records)->cid);
1571 $this->assertSame('4', reset($records)->cid);
a3d5830a 1572
9d6d32b6
PS
1573 // Test 2 tables with aliases and limits with order bys (limit which is highest INT number).
1574 $records = $DB->get_records_sql($sql, null, PHP_INT_MAX, 2); // Skip all courses.
1575 $this->assertCount(0, $records);
a3d5830a 1576
9d6d32b6
PS
1577 // Test 2 tables with aliases and limits with order bys (limit which s highest INT number).
1578 $records = $DB->get_records_sql($sql, null, PHP_INT_MAX, PHP_INT_MAX); // Skip all courses.
1579 $this->assertCount(0, $records);
a3d5830a 1580
9d6d32b6 1581 // TODO: Test limits in queries having DISTINCT clauses.
a3d5830a 1582
9d6d32b6 1583 // Note: fetching nulls, empties, LOBs already tested by test_update_record() no needed here.
a3d5830a
PS
1584 }
1585
1586 public function test_get_records_menu() {
1587 $DB = $this->tdb;
1588 $dbman = $DB->get_manager();
1589
1590 $table = $this->get_test_table();
1591 $tablename = $table->getName();
1592
9d6d32b6
PS
1593 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1594 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1595 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1596 $dbman->create_table($table);
1597
1598 $DB->insert_record($tablename, array('course' => 3));
1599 $DB->insert_record($tablename, array('course' => 3));
1600 $DB->insert_record($tablename, array('course' => 5));
1601 $DB->insert_record($tablename, array('course' => 2));
1602
1603 $records = $DB->get_records_menu($tablename, array('course' => 3));
9d6d32b6
PS
1604 $this->assertInternalType('array', $records);
1605 $this->assertCount(2, $records);
1606 $this->assertNotEmpty($records[1]);
1607 $this->assertNotEmpty($records[2]);
a3d5830a
PS
1608 $this->assertEquals(3, $records[1]);
1609 $this->assertEquals(3, $records[2]);
1610
9d6d32b6 1611 // Note: delegate limits testing to test_get_records_sql().
a3d5830a
PS
1612 }
1613
1614 public function test_get_records_select_menu() {
1615 $DB = $this->tdb;
1616 $dbman = $DB->get_manager();
1617
1618 $table = $this->get_test_table();
1619 $tablename = $table->getName();
1620
9d6d32b6
PS
1621 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1622 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1623 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1624 $dbman->create_table($table);
1625
1626 $DB->insert_record($tablename, array('course' => 3));
1627 $DB->insert_record($tablename, array('course' => 2));
1628 $DB->insert_record($tablename, array('course' => 3));
1629 $DB->insert_record($tablename, array('course' => 5));
1630
1631 $records = $DB->get_records_select_menu($tablename, "course > ?", array(2));
9d6d32b6
PS
1632 $this->assertInternalType('array', $records);
1633
1634 $this->assertCount(3, $records);
1635 $this->assertArrayHasKey(1, $records);
1636 $this->assertArrayNotHasKey(2, $records);
1637 $this->assertArrayHasKey(3, $records);
1638 $this->assertArrayHasKey(4, $records);
1639 $this->assertSame('3', $records[1]);
1640 $this->assertSame('3', $records[3]);
1641 $this->assertSame('5', $records[4]);
1642
1643 // Note: delegate limits testing to test_get_records_sql().
a3d5830a
PS
1644 }
1645
1646 public function test_get_records_sql_menu() {
1647 $DB = $this->tdb;
1648 $dbman = $DB->get_manager();
1649
1650 $table = $this->get_test_table();
1651 $tablename = $table->getName();
1652
9d6d32b6
PS
1653 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1654 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1655 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1656 $dbman->create_table($table);
1657
1658 $DB->insert_record($tablename, array('course' => 3));
1659 $DB->insert_record($tablename, array('course' => 2));
1660 $DB->insert_record($tablename, array('course' => 3));
1661 $DB->insert_record($tablename, array('course' => 5));
1662
1663 $records = $DB->get_records_sql_menu("SELECT * FROM {{$tablename}} WHERE course > ?", array(2));
9d6d32b6
PS
1664 $this->assertInternalType('array', $records);
1665
1666 $this->assertCount(3, $records);
1667 $this->assertArrayHasKey(1, $records);
1668 $this->assertArrayNotHasKey(2, $records);
1669 $this->assertArrayHasKey(3, $records);
1670 $this->assertArrayHasKey(4, $records);
1671 $this->assertSame('3', $records[1]);
1672 $this->assertSame('3', $records[3]);
1673 $this->assertSame('5', $records[4]);
1674
1675 // Note: delegate limits testing to test_get_records_sql().
a3d5830a
PS
1676 }
1677
1678 public function test_get_record() {
1679 $DB = $this->tdb;
1680 $dbman = $DB->get_manager();
1681
1682 $table = $this->get_test_table();
1683 $tablename = $table->getName();
1684
9d6d32b6
PS
1685 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1686 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1687 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1688 $dbman->create_table($table);
1689
1690 $DB->insert_record($tablename, array('course' => 3));
1691 $DB->insert_record($tablename, array('course' => 2));
1692
1693 $record = $DB->get_record($tablename, array('id' => 2));
9d6d32b6 1694 $this->assertInstanceOf('stdClass', $record);
a3d5830a
PS
1695
1696 $this->assertEquals(2, $record->course);
1697 $this->assertEquals(2, $record->id);
1698 }
1699
1700
1701 public function test_get_record_select() {
1702 $DB = $this->tdb;
1703 $dbman = $DB->get_manager();
1704
1705 $table = $this->get_test_table();
1706 $tablename = $table->getName();
1707
9d6d32b6
PS
1708 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1709 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1710 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1711 $dbman->create_table($table);
1712
1713 $DB->insert_record($tablename, array('course' => 3));
1714 $DB->insert_record($tablename, array('course' => 2));
1715
1716 $record = $DB->get_record_select($tablename, "id = ?", array(2));
9d6d32b6 1717 $this->assertInstanceOf('stdClass', $record);
a3d5830a
PS
1718
1719 $this->assertEquals(2, $record->course);
1720
9d6d32b6 1721 // Note: delegates limit testing to test_get_records_sql().
a3d5830a
PS
1722 }
1723
1724 public function test_get_record_sql() {
1725 $DB = $this->tdb;
1726 $dbman = $DB->get_manager();
1727
1728 $table = $this->get_test_table();
1729 $tablename = $table->getName();
1730
9d6d32b6
PS
1731 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1732 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1733 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1734 $dbman->create_table($table);
1735
1736 $DB->insert_record($tablename, array('course' => 3));
1737 $DB->insert_record($tablename, array('course' => 2));
1738
9d6d32b6 1739 // Standard use.
a3d5830a 1740 $record = $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(2));
9d6d32b6 1741 $this->assertInstanceOf('stdClass', $record);
a3d5830a
PS
1742 $this->assertEquals(2, $record->course);
1743 $this->assertEquals(2, $record->id);
1744
9d6d32b6 1745 // Backwards compatibility with $ignoremultiple.
a3d5830a
PS
1746 $this->assertFalse((bool)IGNORE_MISSING);
1747 $this->assertTrue((bool)IGNORE_MULTIPLE);
1748
9d6d32b6 1749 // Record not found - ignore.
a3d5830a
PS
1750 $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MISSING));
1751 $this->assertFalse($DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), IGNORE_MULTIPLE));
1752
9d6d32b6 1753 // Record not found error.
a3d5830a
PS
1754 try {
1755 $DB->get_record_sql("SELECT * FROM {{$tablename}} WHERE id = ?", array(666), MUST_EXIST);
1756 $this->fail("Exception expected");
1757 } catch (dml_missing_record_exception $e) {
1758 $this->assertTrue(true);
1759 }
1760
a3d5830a 1761 $this->assertNotEmpty($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MISSING));
eb10d554 1762 $this->assertDebuggingCalled();
96f81ea3 1763 set_debugging(DEBUG_MINIMAL);
eb10d554
PS
1764 $this->assertNotEmpty($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MISSING));
1765 $this->assertDebuggingNotCalled();
96f81ea3 1766 set_debugging(DEBUG_DEVELOPER);
a3d5830a 1767
9d6d32b6 1768 // Multiple matches ignored.
a3d5830a
PS
1769 $this->assertNotEmpty($DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), IGNORE_MULTIPLE));
1770
9d6d32b6 1771 // Multiple found error.
a3d5830a
PS
1772 try {
1773 $DB->get_record_sql("SELECT * FROM {{$tablename}}", array(), MUST_EXIST);
1774 $this->fail("Exception expected");
1775 } catch (dml_multiple_records_exception $e) {
1776 $this->assertTrue(true);
1777 }
1778 }
1779
1780 public function test_get_field() {
1781 $DB = $this->tdb;
1782 $dbman = $DB->get_manager();
1783
1784 $table = $this->get_test_table();
1785 $tablename = $table->getName();
1786
9d6d32b6
PS
1787 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1788 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1789 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
1790 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1791 $dbman->create_table($table);
1792
1793 $id1 = $DB->insert_record($tablename, array('course' => 3));
1794 $DB->insert_record($tablename, array('course' => 5));
1795 $DB->insert_record($tablename, array('course' => 5));
1796
1797 $this->assertEquals(3, $DB->get_field($tablename, 'course', array('id' => $id1)));
1798 $this->assertEquals(3, $DB->get_field($tablename, 'course', array('course' => 3)));
1799
9d6d32b6 1800 $this->assertFalse($DB->get_field($tablename, 'course', array('course' => 11), IGNORE_MISSING));
a3d5830a
PS
1801 try {
1802 $DB->get_field($tablename, 'course', array('course' => 4), MUST_EXIST);
17222a4a 1803 $this->fail('Exception expected due to missing record');
a3d5830a
PS
1804 } catch (dml_exception $ex) {
1805 $this->assertTrue(true);
1806 }
1807
a3d5830a 1808 $this->assertEquals(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MULTIPLE));
eb10d554 1809 $this->assertDebuggingNotCalled();
a3d5830a 1810
a3d5830a 1811 $this->assertEquals(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MISSING));
eb10d554 1812 $this->assertDebuggingCalled();
a3d5830a 1813
9d6d32b6 1814 // Test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int).
a3d5830a
PS
1815 $conditions = array('onetext' => '1');
1816 try {
1817 $DB->get_field($tablename, 'course', $conditions);
1818 if (debugging()) {
9d6d32b6 1819 // Only in debug mode - hopefully all devs test code in debug mode...
a3d5830a
PS
1820 $this->fail('An Exception is missing, expected due to equating of text fields');
1821 }
9d6d32b6
PS
1822 } catch (moodle_exception $e) {
1823 $this->assertInstanceOf('dml_exception', $e);
1824 $this->assertSame('textconditionsnotallowed', $e->errorcode);
a3d5830a
PS
1825 }
1826 }
1827
1828 public function test_get_field_select() {
1829 $DB = $this->tdb;
1830 $dbman = $DB->get_manager();
1831
1832 $table = $this->get_test_table();
1833 $tablename = $table->getName();
1834
9d6d32b6
PS
1835 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1836 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1837 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1838 $dbman->create_table($table);
1839
1840 $DB->insert_record($tablename, array('course' => 3));
1841
1842 $this->assertEquals(3, $DB->get_field_select($tablename, 'course', "id = ?", array(1)));
1843 }
1844
1845 public function test_get_field_sql() {
1846 $DB = $this->tdb;
1847 $dbman = $DB->get_manager();
1848
1849 $table = $this->get_test_table();
1850 $tablename = $table->getName();
1851
9d6d32b6
PS
1852 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1853 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1854 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1855 $dbman->create_table($table);
1856
1857 $DB->insert_record($tablename, array('course' => 3));
1858
1859 $this->assertEquals(3, $DB->get_field_sql("SELECT course FROM {{$tablename}} WHERE id = ?", array(1)));
1860 }
1861
1862 public function test_get_fieldset_select() {
1863 $DB = $this->tdb;
1864 $dbman = $DB->get_manager();
1865
1866 $table = $this->get_test_table();
1867 $tablename = $table->getName();
1868
9d6d32b6
PS
1869 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1870 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1871 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1872 $dbman->create_table($table);
1873
1874 $DB->insert_record($tablename, array('course' => 1));
1875 $DB->insert_record($tablename, array('course' => 3));
1876 $DB->insert_record($tablename, array('course' => 2));
1877 $DB->insert_record($tablename, array('course' => 6));
1878
1879 $fieldset = $DB->get_fieldset_select($tablename, 'course', "course > ?", array(1));
9d6d32b6 1880 $this->assertInternalType('array', $fieldset);
a3d5830a 1881
9d6d32b6 1882 $this->assertCount(3, $fieldset);
a3d5830a
PS
1883 $this->assertEquals(3, $fieldset[0]);
1884 $this->assertEquals(2, $fieldset[1]);
1885 $this->assertEquals(6, $fieldset[2]);
1886 }
1887
1888 public function test_get_fieldset_sql() {
1889 $DB = $this->tdb;
1890 $dbman = $DB->get_manager();
1891
1892 $table = $this->get_test_table();
1893 $tablename = $table->getName();
1894
9d6d32b6
PS
1895 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1896 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1897 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1898 $dbman->create_table($table);
1899
1900 $DB->insert_record($tablename, array('course' => 1));
1901 $DB->insert_record($tablename, array('course' => 3));
1902 $DB->insert_record($tablename, array('course' => 2));
1903 $DB->insert_record($tablename, array('course' => 6));
1904
1905 $fieldset = $DB->get_fieldset_sql("SELECT * FROM {{$tablename}} WHERE course > ?", array(1));
9d6d32b6 1906 $this->assertInternalType('array', $fieldset);
a3d5830a 1907
9d6d32b6 1908 $this->assertCount(3, $fieldset);
a3d5830a
PS
1909 $this->assertEquals(2, $fieldset[0]);
1910 $this->assertEquals(3, $fieldset[1]);
1911 $this->assertEquals(4, $fieldset[2]);
1912 }
1913
1914 public function test_insert_record_raw() {
1915 $DB = $this->tdb;
1916 $dbman = $DB->get_manager();
1917
1918 $table = $this->get_test_table();
1919 $tablename = $table->getName();
1920
9d6d32b6
PS
1921 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1922 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
1923 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1924 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1925 $dbman->create_table($table);
1926
1927 $record = (object)array('course' => 1, 'onechar' => 'xx');
1928 $before = clone($record);
1929 $result = $DB->insert_record_raw($tablename, $record);
1930 $this->assertSame(1, $result);
1931 $this->assertEquals($record, $before);
1932
1933 $record = $DB->get_record($tablename, array('course' => 1));
9d6d32b6 1934 $this->assertInstanceOf('stdClass', $record);
a3d5830a
PS
1935 $this->assertSame('xx', $record->onechar);
1936
1937 $result = $DB->insert_record_raw($tablename, array('course' => 2, 'onechar' => 'yy'), false);
9d6d32b6 1938 $this->assertTrue($result);
a3d5830a 1939
9d6d32b6 1940 // Note: bulk not implemented yet.
a3d5830a
PS
1941 $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'zz'), true, true);
1942 $record = $DB->get_record($tablename, array('course' => 3));
9d6d32b6 1943 $this->assertInstanceOf('stdClass', $record);
a3d5830a
PS
1944 $this->assertSame('zz', $record->onechar);
1945
9d6d32b6 1946 // Custom sequence (id) - returnid is ignored.
a3d5830a 1947 $result = $DB->insert_record_raw($tablename, array('id' => 10, 'course' => 3, 'onechar' => 'bb'), true, false, true);
9d6d32b6 1948 $this->assertTrue($result);
a3d5830a 1949 $record = $DB->get_record($tablename, array('id' => 10));
9d6d32b6 1950 $this->assertInstanceOf('stdClass', $record);
a3d5830a
PS
1951 $this->assertSame('bb', $record->onechar);
1952
9d6d32b6 1953 // Custom sequence - missing id error.
a3d5830a
PS
1954 try {
1955 $DB->insert_record_raw($tablename, array('course' => 3, 'onechar' => 'bb'), true, false, true);
17222a4a 1956 $this->fail('Exception expected due to missing record');
a3d5830a
PS
1957 } catch (coding_exception $ex) {
1958 $this->assertTrue(true);
1959 }
1960
9d6d32b6 1961 // Wrong column error.
a3d5830a
PS
1962 try {
1963 $DB->insert_record_raw($tablename, array('xxxxx' => 3, 'onechar' => 'bb'));
17222a4a 1964 $this->fail('Exception expected due to invalid column');
a3d5830a
PS
1965 } catch (dml_exception $ex) {
1966 $this->assertTrue(true);
1967 }
3b4f7338 1968
9d6d32b6 1969 // Create something similar to "context_temp" with id column without sequence.
3b4f7338
PS
1970 $dbman->drop_table($table);
1971 $table = $this->get_test_table();
1972 $tablename = $table->getName();
9d6d32b6
PS
1973 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
1974 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
3b4f7338
PS
1975 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
1976 $dbman->create_table($table);
1977
1978 $record = (object)array('id'=>5, 'course' => 1);
1979 $DB->insert_record_raw($tablename, $record, false, false, true);
1980 $record = $DB->get_record($tablename, array());
1981 $this->assertEquals(5, $record->id);
a3d5830a
PS
1982 }
1983
1984 public function test_insert_record() {
1985 // All the information in this test is fetched from DB by get_recordset() so we
1986 // have such method properly tested against nulls, empties and friends...
1987
1988 $DB = $this->tdb;
1989 $dbman = $DB->get_manager();
1990
1991 $table = $this->get_test_table();
1992 $tablename = $table->getName();
1993
9d6d32b6
PS
1994 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
1995 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
1996 $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', null, null, null, 100);
a3d5830a
PS
1997 $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
1998 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
1999 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2000 $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2001 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2002 $dbman->create_table($table);
2003
2004 $this->assertSame(1, $DB->insert_record($tablename, array('course' => 1), true));
2005 $record = $DB->get_record($tablename, array('course' => 1));
2006 $this->assertEquals(1, $record->id);
9d6d32b6 2007 $this->assertEquals(100, $record->oneint); // Just check column defaults have been applied.
a3d5830a
PS
2008 $this->assertEquals(200, $record->onenum);
2009 $this->assertSame('onestring', $record->onechar);
2010 $this->assertNull($record->onetext);
2011 $this->assertNull($record->onebinary);
2012
9d6d32b6
PS
2013 // Without returning id, bulk not implemented.
2014 $result = $this->assertTrue($DB->insert_record($tablename, array('course' => 99), false, true));
a3d5830a
PS
2015 $record = $DB->get_record($tablename, array('course' => 99));
2016 $this->assertEquals(2, $record->id);
2017 $this->assertEquals(99, $record->course);
2018
9d6d32b6 2019 // Check nulls are set properly for all types.
a3d5830a
PS
2020 $record = new stdClass();
2021 $record->oneint = null;
2022 $record->onenum = null;
2023 $record->onechar = null;
2024 $record->onetext = null;
2025 $record->onebinary = null;
2026 $recid = $DB->insert_record($tablename, $record);
2027 $record = $DB->get_record($tablename, array('id' => $recid));
2028 $this->assertEquals(0, $record->course);
2029 $this->assertNull($record->oneint);
2030 $this->assertNull($record->onenum);
2031 $this->assertNull($record->onechar);
2032 $this->assertNull($record->onetext);
2033 $this->assertNull($record->onebinary);
2034
9d6d32b6 2035 // Check zeros are set properly for all types.
a3d5830a
PS
2036 $record = new stdClass();
2037 $record->oneint = 0;
2038 $record->onenum = 0;
2039 $recid = $DB->insert_record($tablename, $record);
2040 $record = $DB->get_record($tablename, array('id' => $recid));
2041 $this->assertEquals(0, $record->oneint);
2042 $this->assertEquals(0, $record->onenum);
2043
9d6d32b6 2044 // Check booleans are set properly for all types.
a3d5830a 2045 $record = new stdClass();
9d6d32b6 2046 $record->oneint = true; // Trues.
a3d5830a
PS
2047 $record->onenum = true;
2048 $record->onechar = true;
2049 $record->onetext = true;
2050 $recid = $DB->insert_record($tablename, $record);
2051 $record = $DB->get_record($tablename, array('id' => $recid));
2052 $this->assertEquals(1, $record->oneint);
2053 $this->assertEquals(1, $record->onenum);
2054 $this->assertEquals(1, $record->onechar);
2055 $this->assertEquals(1, $record->onetext);
2056
2057 $record = new stdClass();
9d6d32b6 2058 $record->oneint = false; // Falses.
a3d5830a
PS
2059 $record->onenum = false;
2060 $record->onechar = false;
2061 $record->onetext = false;
2062 $recid = $DB->insert_record($tablename, $record);
2063 $record = $DB->get_record($tablename, array('id' => $recid));
2064 $this->assertEquals(0, $record->oneint);
2065 $this->assertEquals(0, $record->onenum);
2066 $this->assertEquals(0, $record->onechar);
2067 $this->assertEquals(0, $record->onetext);
2068
9d6d32b6 2069 // Check string data causes exception in numeric types.
a3d5830a
PS
2070 $record = new stdClass();
2071 $record->oneint = 'onestring';
2072 $record->onenum = 0;
2073 try {
2074 $DB->insert_record($tablename, $record);
2075 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2076 } catch (moodle_exception $e) {
2077 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
2078 }
2079 $record = new stdClass();
2080 $record->oneint = 0;
2081 $record->onenum = 'onestring';
2082 try {
2083 $DB->insert_record($tablename, $record);
2084 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2085 } catch (moodle_exception $e) {
2086 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
2087 }
2088
9d6d32b6 2089 // Check empty string data is stored as 0 in numeric datatypes.
a3d5830a 2090 $record = new stdClass();
9d6d32b6 2091 $record->oneint = ''; // Empty string.
a3d5830a
PS
2092 $record->onenum = 0;
2093 $recid = $DB->insert_record($tablename, $record);
2094 $record = $DB->get_record($tablename, array('id' => $recid));
2095 $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
2096
2097 $record = new stdClass();
2098 $record->oneint = 0;
9d6d32b6 2099 $record->onenum = ''; // Empty string.
a3d5830a
PS
2100 $recid = $DB->insert_record($tablename, $record);
2101 $record = $DB->get_record($tablename, array('id' => $recid));
2102 $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
2103
9d6d32b6 2104 // Check empty strings are set properly in string types.
a3d5830a
PS
2105 $record = new stdClass();
2106 $record->oneint = 0;
2107 $record->onenum = 0;
2108 $record->onechar = '';
2109 $record->onetext = '';
2110 $recid = $DB->insert_record($tablename, $record);
2111 $record = $DB->get_record($tablename, array('id' => $recid));
2112 $this->assertTrue($record->onechar === '');
2113 $this->assertTrue($record->onetext === '');
2114
9d6d32b6 2115 // Check operation ((210.10 + 39.92) - 150.02) against numeric types.
a3d5830a
PS
2116 $record = new stdClass();
2117 $record->oneint = ((210.10 + 39.92) - 150.02);
2118 $record->onenum = ((210.10 + 39.92) - 150.02);
2119 $recid = $DB->insert_record($tablename, $record);
2120 $record = $DB->get_record($tablename, array('id' => $recid));
2121 $this->assertEquals(100, $record->oneint);
2122 $this->assertEquals(100, $record->onenum);
2123
9d6d32b6 2124 // Check various quotes/backslashes combinations in string types.
a3d5830a
PS
2125 $teststrings = array(
2126 'backslashes and quotes alone (even): "" \'\' \\\\',
2127 'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2128 'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2129 'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2130 foreach ($teststrings as $teststring) {
2131 $record = new stdClass();
2132 $record->onechar = $teststring;
2133 $record->onetext = $teststring;
2134 $recid = $DB->insert_record($tablename, $record);
2135 $record = $DB->get_record($tablename, array('id' => $recid));
2136 $this->assertEquals($teststring, $record->onechar);
2137 $this->assertEquals($teststring, $record->onetext);
2138 }
2139
9d6d32b6 2140 // Check LOBs in text/binary columns.
a3d5830a
PS
2141 $clob = file_get_contents(__DIR__ . '/fixtures/clob.txt');
2142 $blob = file_get_contents(__DIR__ . '/fixtures/randombinary');
2143 $record = new stdClass();
2144 $record->onetext = $clob;
2145 $record->onebinary = $blob;
2146 $recid = $DB->insert_record($tablename, $record);
2147 $rs = $DB->get_recordset($tablename, array('id' => $recid));
2148 $record = $rs->current();
2149 $rs->close();
2150 $this->assertEquals($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
2151 $this->assertEquals($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
2152
9d6d32b6 2153 // And "small" LOBs too, just in case.
a3d5830a
PS
2154 $newclob = substr($clob, 0, 500);
2155 $newblob = substr($blob, 0, 250);
2156 $record = new stdClass();
2157 $record->onetext = $newclob;
2158 $record->onebinary = $newblob;
2159 $recid = $DB->insert_record($tablename, $record);
2160 $rs = $DB->get_recordset($tablename, array('id' => $recid));
2161 $record = $rs->current();
2162 $rs->close();
2163 $this->assertEquals($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
2164 $this->assertEquals($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
9d6d32b6 2165 $this->assertEquals(false, $rs->key()); // Ensure recordset key() method to be working ok after closing.
a3d5830a 2166
9d6d32b6 2167 // And "diagnostic" LOBs too, just in case.
a3d5830a
PS
2168 $newclob = '\'"\\;/ěščřžýáíé';
2169 $newblob = '\'"\\;/ěščřžýáíé';
2170 $record = new stdClass();
2171 $record->onetext = $newclob;
2172 $record->onebinary = $newblob;
2173 $recid = $DB->insert_record($tablename, $record);
2174 $rs = $DB->get_recordset($tablename, array('id' => $recid));
2175 $record = $rs->current();
2176 $rs->close();
2177 $this->assertSame($newclob, $record->onetext);
2178 $this->assertSame($newblob, $record->onebinary);
9d6d32b6 2179 $this->assertEquals(false, $rs->key()); // Ensure recordset key() method to be working ok after closing.
a3d5830a 2180
9d6d32b6 2181 // Test data is not modified.
a3d5830a 2182 $record = new stdClass();
9d6d32b6 2183 $record->id = -1; // Has to be ignored.
a3d5830a 2184 $record->course = 3;
9d6d32b6 2185 $record->lalala = 'lalal'; // Unused.
a3d5830a
PS
2186 $before = clone($record);
2187 $DB->insert_record($tablename, $record);
2188 $this->assertEquals($record, $before);
2189
9d6d32b6 2190 // Make sure the id is always increasing and never reuses the same id.
a3d5830a
PS
2191 $id1 = $DB->insert_record($tablename, array('course' => 3));
2192 $id2 = $DB->insert_record($tablename, array('course' => 3));
2193 $this->assertTrue($id1 < $id2);
2194 $DB->delete_records($tablename, array('id'=>$id2));
2195 $id3 = $DB->insert_record($tablename, array('course' => 3));
2196 $this->assertTrue($id2 < $id3);
2197 $DB->delete_records($tablename, array());
2198 $id4 = $DB->insert_record($tablename, array('course' => 3));
2199 $this->assertTrue($id3 < $id4);
2200
2201 // Test saving a float in a CHAR column, and reading it back.
2202 $id = $DB->insert_record($tablename, array('onechar' => 1.0));
2203 $this->assertEquals(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2204 $id = $DB->insert_record($tablename, array('onechar' => 1e20));
2205 $this->assertEquals(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2206 $id = $DB->insert_record($tablename, array('onechar' => 1e-4));
2207 $this->assertEquals(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2208 $id = $DB->insert_record($tablename, array('onechar' => 1e-5));
2209 $this->assertEquals(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2210 $id = $DB->insert_record($tablename, array('onechar' => 1e-300));
2211 $this->assertEquals(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2212 $id = $DB->insert_record($tablename, array('onechar' => 1e300));
2213 $this->assertEquals(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2214
2215 // Test saving a float in a TEXT column, and reading it back.
2216 $id = $DB->insert_record($tablename, array('onetext' => 1.0));
2217 $this->assertEquals(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2218 $id = $DB->insert_record($tablename, array('onetext' => 1e20));
2219 $this->assertEquals(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2220 $id = $DB->insert_record($tablename, array('onetext' => 1e-4));
2221 $this->assertEquals(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2222 $id = $DB->insert_record($tablename, array('onetext' => 1e-5));
2223 $this->assertEquals(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2224 $id = $DB->insert_record($tablename, array('onetext' => 1e-300));
2225 $this->assertEquals(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2226 $id = $DB->insert_record($tablename, array('onetext' => 1e300));
2227 $this->assertEquals(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
cbdcdd47
EL
2228
2229 // Test that inserting data violating one unique key leads to error.
2230 // Empty the table completely.
2231 $this->assertTrue($DB->delete_records($tablename));
2232
2233 // Add one unique constraint (index).
2234 $key = new xmldb_key('testuk', XMLDB_KEY_UNIQUE, array('course', 'oneint'));
2235 $dbman->add_key($table, $key);
2236
2237 // Let's insert one record violating the constraint multiple times.
2238 $record = (object)array('course' => 1, 'oneint' => 1);
9d6d32b6 2239 $this->assertTrue($DB->insert_record($tablename, $record, false)); // Insert 1st. No problem expected.
cbdcdd47
EL
2240
2241 // Re-insert same record, not returning id. dml_exception expected.
2242 try {
2243 $DB->insert_record($tablename, $record, false);
2244 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2245 } catch (moodle_exception $e) {
2246 $this->assertInstanceOf('dml_exception', $e);
cbdcdd47
EL
2247 }
2248
2249 // Re-insert same record, returning id. dml_exception expected.
2250 try {
2251 $DB->insert_record($tablename, $record, true);
2252 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2253 } catch (moodle_exception $e) {
2254 $this->assertInstanceOf('dml_exception', $e);
cbdcdd47 2255 }
9c7dfbe6
RS
2256
2257 // Try to insert a record into a non-existent table. dml_exception expected.
2258 try {
2259 $DB->insert_record('nonexistenttable', $record, true);
2260 $this->fail("Expecting an exception, none occurred");
2261 } catch (exception $e) {
2262 $this->assertTrue($e instanceof dml_exception);
2263 }
a3d5830a
PS
2264 }
2265
cc5dba8e
2266 public function test_insert_records() {
2267 $DB = $this->tdb;
2268 $dbman = $DB->get_manager();
2269
2270 $table = $this->get_test_table();
2271 $tablename = $table->getName();
2272
2273 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2274 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
2275 $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', null, null, null, 100);
2276 $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
2277 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
2278 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2279 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2280 $dbman->create_table($table);
2281
2282 $this->assertCount(0, $DB->get_records($tablename));
2283
2284 $record = new stdClass();
2285 $record->id = '1';
2286 $record->course = '1';
2287 $record->oneint = null;
2288 $record->onenum = '1.00';
2289 $record->onechar = 'a';
2290 $record->onetext = 'aaa';
2291
2292 $expected = array();
2293 $records = array();
2294 for ($i = 1; $i <= 2000; $i++) { // This may take a while, it should be higher than defaults in DML drivers.
2295 $rec = clone($record);
2296 $rec->id = (string)$i;
2297 $rec->oneint = (string)$i;
2298 $expected[$i] = $rec;
2299 $rec = clone($rec);
2300 unset($rec->id);
2301 $records[$i] = $rec;
2302 }
2303
2304 $DB->insert_records($tablename, $records);
2305 $stored = $DB->get_records($tablename, array(), 'id ASC');
2306 $this->assertEquals($expected, $stored);
2307
2308 // Test there can be some extra properties including id.
2309 $count = $DB->count_records($tablename);
2310 $rec1 = (array)$record;
2311 $rec1['xxx'] = 1;
2312 $rec2 = (array)$record;
2313 $rec2['xxx'] = 2;
2314
2315 $records = array($rec1, $rec2);
2316 $DB->insert_records($tablename, $records);
2317 $this->assertEquals($count + 2, $DB->count_records($tablename));
2318
2319 // Test not all properties are necessary.
2320 $rec1 = (array)$record;
2321 unset($rec1['course']);
2322 $rec2 = (array)$record;
2323 unset($rec2['course']);
2324
2325 $records = array($rec1, $rec2);
2326 $DB->insert_records($tablename, $records);
2327
2328 // Make sure no changes in data object structure are tolerated.
2329 $rec1 = (array)$record;
2330 unset($rec1['id']);
2331 $rec2 = (array)$record;
2332 unset($rec2['id']);
2333
2334 $records = array($rec1, $rec2);
2335 $DB->insert_records($tablename, $records);
2336
2337 $rec2['xx'] = '1';
2338 $records = array($rec1, $rec2);
2339 try {
2340 $DB->insert_records($tablename, $records);
2341 $this->fail('coding_exception expected when insert_records receives different object data structures');
2342 } catch (moodle_exception $e) {
2343 $this->assertInstanceOf('coding_exception', $e);
2344 }
2345
2346 unset($rec2['xx']);
2347 unset($rec2['course']);
2348 $rec2['course'] = '1';
2349 $records = array($rec1, $rec2);
2350 try {
2351 $DB->insert_records($tablename, $records);
2352 $this->fail('coding_exception expected when insert_records receives different object data structures');
2353 } catch (moodle_exception $e) {
2354 $this->assertInstanceOf('coding_exception', $e);
2355 }
2356
2357 $records = 1;
2358 try {
2359 $DB->insert_records($tablename, $records);
2360 $this->fail('coding_exception expected when insert_records receives non-traversable data');
2361 } catch (moodle_exception $e) {
2362 $this->assertInstanceOf('coding_exception', $e);
2363 }
2364
2365 $records = array(1);
2366 try {
2367 $DB->insert_records($tablename, $records);
2368 $this->fail('coding_exception expected when insert_records receives non-objet record');
2369 } catch (moodle_exception $e) {
2370 $this->assertInstanceOf('coding_exception', $e);
2371 }
2372 }
2373
a3d5830a
PS
2374 public function test_import_record() {
2375 // All the information in this test is fetched from DB by get_recordset() so we
2376 // have such method properly tested against nulls, empties and friends...
2377
2378 $DB = $this->tdb;
2379 $dbman = $DB->get_manager();
2380
2381 $table = $this->get_test_table();
2382 $tablename = $table->getName();
2383
9d6d32b6
PS
2384 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2385 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
2386 $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', null, null, null, 100);
a3d5830a
PS
2387 $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
2388 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
2389 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2390 $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2391 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2392 $dbman->create_table($table);
2393
2394 $this->assertSame(1, $DB->insert_record($tablename, array('course' => 1), true));
2395 $record = $DB->get_record($tablename, array('course' => 1));
2396 $this->assertEquals(1, $record->id);
9d6d32b6 2397 $this->assertEquals(100, $record->oneint); // Just check column defaults have been applied.
a3d5830a
PS
2398 $this->assertEquals(200, $record->onenum);
2399 $this->assertSame('onestring', $record->onechar);
2400 $this->assertNull($record->onetext);
2401 $this->assertNull($record->onebinary);
2402
9d6d32b6 2403 // Ignore extra columns.
a3d5830a
PS
2404 $record = (object)array('id'=>13, 'course'=>2, 'xxxx'=>788778);
2405 $before = clone($record);
9d6d32b6 2406 $this->assertTrue($DB->import_record($tablename, $record));
a3d5830a
PS
2407 $this->assertEquals($record, $before);
2408 $records = $DB->get_records($tablename);
2409 $this->assertEquals(2, $records[13]->course);
2410
9d6d32b6 2411 // Check nulls are set properly for all types.
a3d5830a
PS
2412 $record = new stdClass();
2413 $record->id = 20;
2414 $record->oneint = null;
2415 $record->onenum = null;
2416 $record->onechar = null;
2417 $record->onetext = null;
2418 $record->onebinary = null;
2419 $this->assertTrue($DB->import_record($tablename, $record));
2420 $record = $DB->get_record($tablename, array('id' => 20));
2421 $this->assertEquals(0, $record->course);
2422 $this->assertNull($record->oneint);
2423 $this->assertNull($record->onenum);
2424 $this->assertNull($record->onechar);
2425 $this->assertNull($record->onetext);
2426 $this->assertNull($record->onebinary);
2427
9d6d32b6 2428 // Check zeros are set properly for all types.
a3d5830a
PS
2429 $record = new stdClass();
2430 $record->id = 23;
2431 $record->oneint = 0;
2432 $record->onenum = 0;
2433 $this->assertTrue($DB->import_record($tablename, $record));
2434 $record = $DB->get_record($tablename, array('id' => 23));
2435 $this->assertEquals(0, $record->oneint);
2436 $this->assertEquals(0, $record->onenum);
2437
9d6d32b6 2438 // Check string data causes exception in numeric types.
a3d5830a
PS
2439 $record = new stdClass();
2440 $record->id = 32;
2441 $record->oneint = 'onestring';
2442 $record->onenum = 0;
2443 try {
2444 $DB->import_record($tablename, $record);
2445 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2446 } catch (moodle_exception $e) {
2447 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
2448 }
2449 $record = new stdClass();
2450 $record->id = 35;
2451 $record->oneint = 0;
2452 $record->onenum = 'onestring';
2453 try {
2454 $DB->import_record($tablename, $record);
2455 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2456 } catch (moodle_exception $e) {
2457 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
2458 }
2459
9d6d32b6 2460 // Check empty strings are set properly in string types.
a3d5830a
PS
2461 $record = new stdClass();
2462 $record->id = 44;
2463 $record->oneint = 0;
2464 $record->onenum = 0;
2465 $record->onechar = '';
2466 $record->onetext = '';
2467 $this->assertTrue($DB->import_record($tablename, $record));
2468 $record = $DB->get_record($tablename, array('id' => 44));
2469 $this->assertTrue($record->onechar === '');
2470 $this->assertTrue($record->onetext === '');
2471
9d6d32b6 2472 // Check operation ((210.10 + 39.92) - 150.02) against numeric types.
a3d5830a
PS
2473 $record = new stdClass();
2474 $record->id = 47;
2475 $record->oneint = ((210.10 + 39.92) - 150.02);
2476 $record->onenum = ((210.10 + 39.92) - 150.02);
2477 $this->assertTrue($DB->import_record($tablename, $record));
2478 $record = $DB->get_record($tablename, array('id' => 47));
2479 $this->assertEquals(100, $record->oneint);
2480 $this->assertEquals(100, $record->onenum);
2481
9d6d32b6 2482 // Check various quotes/backslashes combinations in string types.
a3d5830a
PS
2483 $i = 50;
2484 $teststrings = array(
2485 'backslashes and quotes alone (even): "" \'\' \\\\',
2486 'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2487 'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2488 'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2489 foreach ($teststrings as $teststring) {
2490 $record = new stdClass();
2491 $record->id = $i;
2492 $record->onechar = $teststring;
2493 $record->onetext = $teststring;
2494 $this->assertTrue($DB->import_record($tablename, $record));
2495 $record = $DB->get_record($tablename, array('id' => $i));
2496 $this->assertEquals($teststring, $record->onechar);
2497 $this->assertEquals($teststring, $record->onetext);
2498 $i = $i + 3;
2499 }
2500
9d6d32b6 2501 // Check LOBs in text/binary columns.
a3d5830a
PS
2502 $clob = file_get_contents(__DIR__ . '/fixtures/clob.txt');
2503 $record = new stdClass();
2504 $record->id = 70;
2505 $record->onetext = $clob;
2506 $record->onebinary = '';
2507 $this->assertTrue($DB->import_record($tablename, $record));
2508 $rs = $DB->get_recordset($tablename, array('id' => 70));
2509 $record = $rs->current();
2510 $rs->close();
2511 $this->assertEquals($clob, $record->onetext, 'Test CLOB insert (full contents output disabled)');
2512
2513 $blob = file_get_contents(__DIR__ . '/fixtures/randombinary');
2514 $record = new stdClass();
2515 $record->id = 71;
2516 $record->onetext = '';
2517 $record->onebinary = $blob;
2518 $this->assertTrue($DB->import_record($tablename, $record));
2519 $rs = $DB->get_recordset($tablename, array('id' => 71));
2520 $record = $rs->current();
2521 $rs->close();
2522 $this->assertEquals($blob, $record->onebinary, 'Test BLOB insert (full contents output disabled)');
2523
9d6d32b6 2524 // And "small" LOBs too, just in case.
a3d5830a
PS
2525 $newclob = substr($clob, 0, 500);
2526 $newblob = substr($blob, 0, 250);
2527 $record = new stdClass();
2528 $record->id = 73;
2529 $record->onetext = $newclob;
2530 $record->onebinary = $newblob;
2531 $this->assertTrue($DB->import_record($tablename, $record));
2532 $rs = $DB->get_recordset($tablename, array('id' => 73));
2533 $record = $rs->current();
2534 $rs->close();
2535 $this->assertEquals($newclob, $record->onetext, 'Test "small" CLOB insert (full contents output disabled)');
2536 $this->assertEquals($newblob, $record->onebinary, 'Test "small" BLOB insert (full contents output disabled)');
9d6d32b6 2537 $this->assertEquals(false, $rs->key()); // Ensure recordset key() method to be working ok after closing.
a3d5830a
PS
2538 }
2539
2540 public function test_update_record_raw() {
2541 $DB = $this->tdb;
2542 $dbman = $DB->get_manager();
2543
2544 $table = $this->get_test_table();
2545 $tablename = $table->getName();
2546
9d6d32b6
PS
2547 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2548 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
2549 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2550 $dbman->create_table($table);
2551
2552 $DB->insert_record($tablename, array('course' => 1));
2553 $DB->insert_record($tablename, array('course' => 3));
2554
2555 $record = $DB->get_record($tablename, array('course' => 1));
2556 $record->course = 2;
2557 $this->assertTrue($DB->update_record_raw($tablename, $record));
2558 $this->assertEquals(0, $DB->count_records($tablename, array('course' => 1)));
2559 $this->assertEquals(1, $DB->count_records($tablename, array('course' => 2)));
2560 $this->assertEquals(1, $DB->count_records($tablename, array('course' => 3)));
2561
2562 $record = $DB->get_record($tablename, array('course' => 3));
2563 $record->xxxxx = 2;
2564 try {
2565 $DB->update_record_raw($tablename, $record);
2566 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2567 } catch (moodle_exception $e) {
2568 $this->assertInstanceOf('moodle_exception', $e);
a3d5830a
PS
2569 }
2570
2571 $record = $DB->get_record($tablename, array('course' => 3));
2572 unset($record->id);
2573 try {
2574 $DB->update_record_raw($tablename, $record);
2575 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2576 } catch (moodle_exception $e) {
2577 $this->assertInstanceOf('coding_exception', $e);
a3d5830a
PS
2578 }
2579 }
2580
2581 public function test_update_record() {
2582
2583 // All the information in this test is fetched from DB by get_record() so we
2584 // have such method properly tested against nulls, empties and friends...
2585
2586 $DB = $this->tdb;
2587 $dbman = $DB->get_manager();
2588
2589 $table = $this->get_test_table();
2590 $tablename = $table->getName();
2591
9d6d32b6
PS
2592 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2593 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
2594 $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', null, null, null, 100);
a3d5830a
PS
2595 $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
2596 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null, 'onestring');
2597 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2598 $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2599 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2600 $dbman->create_table($table);
2601
2602 $DB->insert_record($tablename, array('course' => 1));
2603 $record = $DB->get_record($tablename, array('course' => 1));
2604 $record->course = 2;
2605
2606 $this->assertTrue($DB->update_record($tablename, $record));
2607 $this->assertFalse($record = $DB->get_record($tablename, array('course' => 1)));
2608 $this->assertNotEmpty($record = $DB->get_record($tablename, array('course' => 2)));
9d6d32b6 2609 $this->assertEquals(100, $record->oneint); // Just check column defaults have been applied.
a3d5830a 2610 $this->assertEquals(200, $record->onenum);
9d6d32b6 2611 $this->assertSame('onestring', $record->onechar);
a3d5830a
PS
2612 $this->assertNull($record->onetext);
2613 $this->assertNull($record->onebinary);
2614
9d6d32b6 2615 // Check nulls are set properly for all types.
a3d5830a
PS
2616 $record->oneint = null;
2617 $record->onenum = null;
2618 $record->onechar = null;
2619 $record->onetext = null;
2620 $record->onebinary = null;
2621 $DB->update_record($tablename, $record);
2622 $record = $DB->get_record($tablename, array('course' => 2));
2623 $this->assertNull($record->oneint);
2624 $this->assertNull($record->onenum);
2625 $this->assertNull($record->onechar);
2626 $this->assertNull($record->onetext);
2627 $this->assertNull($record->onebinary);
2628
9d6d32b6 2629 // Check zeros are set properly for all types.
a3d5830a
PS
2630 $record->oneint = 0;
2631 $record->onenum = 0;
2632 $DB->update_record($tablename, $record);
2633 $record = $DB->get_record($tablename, array('course' => 2));
2634 $this->assertEquals(0, $record->oneint);
2635 $this->assertEquals(0, $record->onenum);
2636
9d6d32b6
PS
2637 // Check booleans are set properly for all types.
2638 $record->oneint = true; // Trues.
a3d5830a
PS
2639 $record->onenum = true;
2640 $record->onechar = true;
2641 $record->onetext = true;
2642 $DB->update_record($tablename, $record);
2643 $record = $DB->get_record($tablename, array('course' => 2));
2644 $this->assertEquals(1, $record->oneint);
2645 $this->assertEquals(1, $record->onenum);
2646 $this->assertEquals(1, $record->onechar);
2647 $this->assertEquals(1, $record->onetext);
2648
9d6d32b6 2649 $record->oneint = false; // Falses.
a3d5830a
PS
2650 $record->onenum = false;
2651 $record->onechar = false;
2652 $record->onetext = false;
2653 $DB->update_record($tablename, $record);
2654 $record = $DB->get_record($tablename, array('course' => 2));
2655 $this->assertEquals(0, $record->oneint);
2656 $this->assertEquals(0, $record->onenum);
2657 $this->assertEquals(0, $record->onechar);
2658 $this->assertEquals(0, $record->onetext);
2659
9d6d32b6 2660 // Check string data causes exception in numeric types.
a3d5830a
PS
2661 $record->oneint = 'onestring';
2662 $record->onenum = 0;
2663 try {
2664 $DB->update_record($tablename, $record);
2665 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2666 } catch (moodle_exception $e) {
2667 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
2668 }
2669 $record->oneint = 0;
2670 $record->onenum = 'onestring';
2671 try {
2672 $DB->update_record($tablename, $record);
2673 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2674 } catch (moodle_exception $e) {
2675 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
2676 }
2677
9d6d32b6
PS
2678 // Check empty string data is stored as 0 in numeric datatypes.
2679 $record->oneint = ''; // Empty string.
a3d5830a
PS
2680 $record->onenum = 0;
2681 $DB->update_record($tablename, $record);
2682 $record = $DB->get_record($tablename, array('course' => 2));
2683 $this->assertTrue(is_numeric($record->oneint) && $record->oneint == 0);
2684
2685 $record->oneint = 0;
9d6d32b6 2686 $record->onenum = ''; // Empty string.
a3d5830a
PS
2687 $DB->update_record($tablename, $record);
2688 $record = $DB->get_record($tablename, array('course' => 2));
2689 $this->assertTrue(is_numeric($record->onenum) && $record->onenum == 0);
2690
9d6d32b6 2691 // Check empty strings are set properly in string types.
a3d5830a
PS
2692 $record->oneint = 0;
2693 $record->onenum = 0;
2694 $record->onechar = '';
2695 $record->onetext = '';
2696 $DB->update_record($tablename, $record);
2697 $record = $DB->get_record($tablename, array('course' => 2));
2698 $this->assertTrue($record->onechar === '');
2699 $this->assertTrue($record->onetext === '');
2700
9d6d32b6 2701 // Check operation ((210.10 + 39.92) - 150.02) against numeric types.
a3d5830a
PS
2702 $record->oneint = ((210.10 + 39.92) - 150.02);
2703 $record->onenum = ((210.10 + 39.92) - 150.02);
2704 $DB->update_record($tablename, $record);
2705 $record = $DB->get_record($tablename, array('course' => 2));
2706 $this->assertEquals(100, $record->oneint);
2707 $this->assertEquals(100, $record->onenum);
2708
9d6d32b6 2709 // Check various quotes/backslashes combinations in string types.
a3d5830a
PS
2710 $teststrings = array(
2711 'backslashes and quotes alone (even): "" \'\' \\\\',
2712 'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2713 'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2714 'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2715 foreach ($teststrings as $teststring) {
2716 $record->onechar = $teststring;
2717 $record->onetext = $teststring;
2718 $DB->update_record($tablename, $record);
2719 $record = $DB->get_record($tablename, array('course' => 2));
2720 $this->assertEquals($teststring, $record->onechar);
2721 $this->assertEquals($teststring, $record->onetext);
2722 }
2723
9d6d32b6 2724 // Check LOBs in text/binary columns.
a3d5830a
PS
2725 $clob = file_get_contents(__DIR__ . '/fixtures/clob.txt');
2726 $blob = file_get_contents(__DIR__ . '/fixtures/randombinary');
2727 $record->onetext = $clob;
2728 $record->onebinary = $blob;
2729 $DB->update_record($tablename, $record);
2730 $record = $DB->get_record($tablename, array('course' => 2));
2731 $this->assertEquals($clob, $record->onetext, 'Test CLOB update (full contents output disabled)');
2732 $this->assertEquals($blob, $record->onebinary, 'Test BLOB update (full contents output disabled)');
2733
9d6d32b6 2734 // And "small" LOBs too, just in case.
a3d5830a
PS
2735 $newclob = substr($clob, 0, 500);
2736 $newblob = substr($blob, 0, 250);
2737 $record->onetext = $newclob;
2738 $record->onebinary = $newblob;
2739 $DB->update_record($tablename, $record);
2740 $record = $DB->get_record($tablename, array('course' => 2));
2741 $this->assertEquals($newclob, $record->onetext, 'Test "small" CLOB update (full contents output disabled)');
2742 $this->assertEquals($newblob, $record->onebinary, 'Test "small" BLOB update (full contents output disabled)');
2743
2744 // Test saving a float in a CHAR column, and reading it back.
2745 $id = $DB->insert_record($tablename, array('onechar' => 'X'));
2746 $DB->update_record($tablename, array('id' => $id, 'onechar' => 1.0));
2747 $this->assertEquals(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2748 $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e20));
2749 $this->assertEquals(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2750 $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-4));
2751 $this->assertEquals(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2752 $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-5));
2753 $this->assertEquals(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2754 $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e-300));
2755 $this->assertEquals(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2756 $DB->update_record($tablename, array('id' => $id, 'onechar' => 1e300));
2757 $this->assertEquals(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2758
2759 // Test saving a float in a TEXT column, and reading it back.
2760 $id = $DB->insert_record($tablename, array('onetext' => 'X'));
2761 $DB->update_record($tablename, array('id' => $id, 'onetext' => 1.0));
2762 $this->assertEquals(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2763 $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e20));
2764 $this->assertEquals(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2765 $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-4));
2766 $this->assertEquals(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2767 $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-5));
2768 $this->assertEquals(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2769 $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e-300));
2770 $this->assertEquals(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2771 $DB->update_record($tablename, array('id' => $id, 'onetext' => 1e300));
2772 $this->assertEquals(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2773 }
2774
2775 public function test_set_field() {
2776 $DB = $this->tdb;
2777 $dbman = $DB->get_manager();
2778
2779 $table = $this->get_test_table();
2780 $tablename = $table->getName();
2781
9d6d32b6
PS
2782 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2783 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
2784 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
2785 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2786 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2787 $dbman->create_table($table);
2788
9d6d32b6 2789 // Simple set_field.
a3d5830a
PS
2790 $id1 = $DB->insert_record($tablename, array('course' => 1));
2791 $id2 = $DB->insert_record($tablename, array('course' => 1));
2792 $id3 = $DB->insert_record($tablename, array('course' => 3));
2793 $this->assertTrue($DB->set_field($tablename, 'course', 2, array('id' => $id1)));
2794 $this->assertEquals(2, $DB->get_field($tablename, 'course', array('id' => $id1)));
2795 $this->assertEquals(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
2796 $this->assertEquals(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2797 $DB->delete_records($tablename, array());
2798
9d6d32b6 2799 // Multiple fields affected.
a3d5830a
PS
2800 $id1 = $DB->insert_record($tablename, array('course' => 1));
2801 $id2 = $DB->insert_record($tablename, array('course' => 1));
2802 $id3 = $DB->insert_record($tablename, array('course' => 3));
2803 $DB->set_field($tablename, 'course', '5', array('course' => 1));
2804 $this->assertEquals(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
2805 $this->assertEquals(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
2806 $this->assertEquals(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2807 $DB->delete_records($tablename, array());
2808
9d6d32b6 2809 // No field affected.
a3d5830a
PS
2810 $id1 = $DB->insert_record($tablename, array('course' => 1));
2811 $id2 = $DB->insert_record($tablename, array('course' => 1));
2812 $id3 = $DB->insert_record($tablename, array('course' => 3));
2813 $DB->set_field($tablename, 'course', '5', array('course' => 0));
2814 $this->assertEquals(1, $DB->get_field($tablename, 'course', array('id' => $id1)));
2815 $this->assertEquals(1, $DB->get_field($tablename, 'course', array('id' => $id2)));
2816 $this->assertEquals(3, $DB->get_field($tablename, 'course', array('id' => $id3)));
2817 $DB->delete_records($tablename, array());
2818
9d6d32b6 2819 // All fields - no condition.
a3d5830a
PS
2820 $id1 = $DB->insert_record($tablename, array('course' => 1));
2821 $id2 = $DB->insert_record($tablename, array('course' => 1));
2822 $id3 = $DB->insert_record($tablename, array('course' => 3));
2823 $DB->set_field($tablename, 'course', 5, array());
2824 $this->assertEquals(5, $DB->get_field($tablename, 'course', array('id' => $id1)));
2825 $this->assertEquals(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
2826 $this->assertEquals(5, $DB->get_field($tablename, 'course', array('id' => $id3)));
2827
9d6d32b6 2828 // Test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int).
a3d5830a
PS
2829 $conditions = array('onetext' => '1');
2830 try {
2831 $DB->set_field($tablename, 'onechar', 'frog', $conditions);
2832 if (debugging()) {
9d6d32b6 2833 // Only in debug mode - hopefully all devs test code in debug mode...
a3d5830a
PS
2834 $this->fail('An Exception is missing, expected due to equating of text fields');
2835 }
9d6d32b6
PS
2836 } catch (moodle_exception $e) {
2837 $this->assertInstanceOf('dml_exception', $e);
2838 $this->assertSame('textconditionsnotallowed', $e->errorcode);
a3d5830a
PS
2839 }
2840
2841 // Test saving a float in a CHAR column, and reading it back.
2842 $id = $DB->insert_record($tablename, array('onechar' => 'X'));
2843 $DB->set_field($tablename, 'onechar', 1.0, array('id' => $id));
2844 $this->assertEquals(1.0, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2845 $DB->set_field($tablename, 'onechar', 1e20, array('id' => $id));
2846 $this->assertEquals(1e20, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2847 $DB->set_field($tablename, 'onechar', 1e-4, array('id' => $id));
2848 $this->assertEquals(1e-4, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2849 $DB->set_field($tablename, 'onechar', 1e-5, array('id' => $id));
2850 $this->assertEquals(1e-5, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2851 $DB->set_field($tablename, 'onechar', 1e-300, array('id' => $id));
2852 $this->assertEquals(1e-300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2853 $DB->set_field($tablename, 'onechar', 1e300, array('id' => $id));
2854 $this->assertEquals(1e300, $DB->get_field($tablename, 'onechar', array('id' => $id)));
2855
2856 // Test saving a float in a TEXT column, and reading it back.
2857 $id = $DB->insert_record($tablename, array('onetext' => 'X'));
2858 $DB->set_field($tablename, 'onetext', 1.0, array('id' => $id));
2859 $this->assertEquals(1.0, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2860 $DB->set_field($tablename, 'onetext', 1e20, array('id' => $id));
2861 $this->assertEquals(1e20, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2862 $DB->set_field($tablename, 'onetext', 1e-4, array('id' => $id));
2863 $this->assertEquals(1e-4, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2864 $DB->set_field($tablename, 'onetext', 1e-5, array('id' => $id));
2865 $this->assertEquals(1e-5, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2866 $DB->set_field($tablename, 'onetext', 1e-300, array('id' => $id));
2867 $this->assertEquals(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2868 $DB->set_field($tablename, 'onetext', 1e300, array('id' => $id));
2869 $this->assertEquals(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
2870
2871 // Note: All the nulls, booleans, empties, quoted and backslashes tests
9d6d32b6 2872 // go to set_field_select() because set_field() is just one wrapper over it.
a3d5830a
PS
2873 }
2874
2875 public function test_set_field_select() {
2876
2877 // All the information in this test is fetched from DB by get_field() so we
2878 // have such method properly tested against nulls, empties and friends...
2879
2880 $DB = $this->tdb;
2881 $dbman = $DB->get_manager();
2882
2883 $table = $this->get_test_table();
2884 $tablename = $table->getName();
2885
9d6d32b6
PS
2886 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
2887 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
2888 $table->add_field('oneint', XMLDB_TYPE_INTEGER, '10', null, null, null);
a3d5830a
PS
2889 $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null);
2890 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
2891 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
2892 $table->add_field('onebinary', XMLDB_TYPE_BINARY, 'big', null, null, null);
2893 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
2894 $dbman->create_table($table);
2895
2896 $DB->insert_record($tablename, array('course' => 1));
2897
2898 $this->assertTrue($DB->set_field_select($tablename, 'course', 2, 'id = ?', array(1)));
2899 $this->assertEquals(2, $DB->get_field($tablename, 'course', array('id' => 1)));
2900
9d6d32b6
PS
2901 // Check nulls are set properly for all types.
2902 $DB->set_field_select($tablename, 'oneint', null, 'id = ?', array(1)); // Trues.
a3d5830a
PS
2903 $DB->set_field_select($tablename, 'onenum', null, 'id = ?', array(1));
2904 $DB->set_field_select($tablename, 'onechar', null, 'id = ?', array(1));
2905 $DB->set_field_select($tablename, 'onetext', null, 'id = ?', array(1));
2906 $DB->set_field_select($tablename, 'onebinary', null, 'id = ?', array(1));
2907 $this->assertNull($DB->get_field($tablename, 'oneint', array('id' => 1)));
2908 $this->assertNull($DB->get_field($tablename, 'onenum', array('id' => 1)));
2909 $this->assertNull($DB->get_field($tablename, 'onechar', array('id' => 1)));
2910 $this->assertNull($DB->get_field($tablename, 'onetext', array('id' => 1)));
2911 $this->assertNull($DB->get_field($tablename, 'onebinary', array('id' => 1)));
2912
9d6d32b6 2913 // Check zeros are set properly for all types.
a3d5830a
PS
2914 $DB->set_field_select($tablename, 'oneint', 0, 'id = ?', array(1));
2915 $DB->set_field_select($tablename, 'onenum', 0, 'id = ?', array(1));
2916 $this->assertEquals(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2917 $this->assertEquals(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2918
9d6d32b6
PS
2919 // Check booleans are set properly for all types.
2920 $DB->set_field_select($tablename, 'oneint', true, 'id = ?', array(1)); // Trues.
a3d5830a
PS
2921 $DB->set_field_select($tablename, 'onenum', true, 'id = ?', array(1));
2922 $DB->set_field_select($tablename, 'onechar', true, 'id = ?', array(1));
2923 $DB->set_field_select($tablename, 'onetext', true, 'id = ?', array(1));
2924 $this->assertEquals(1, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2925 $this->assertEquals(1, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2926 $this->assertEquals(1, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2927 $this->assertEquals(1, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2928
9d6d32b6 2929 $DB->set_field_select($tablename, 'oneint', false, 'id = ?', array(1)); // Falses.
a3d5830a
PS
2930 $DB->set_field_select($tablename, 'onenum', false, 'id = ?', array(1));
2931 $DB->set_field_select($tablename, 'onechar', false, 'id = ?', array(1));
2932 $DB->set_field_select($tablename, 'onetext', false, 'id = ?', array(1));
2933 $this->assertEquals(0, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2934 $this->assertEquals(0, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2935 $this->assertEquals(0, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2936 $this->assertEquals(0, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2937
9d6d32b6 2938 // Check string data causes exception in numeric types.
a3d5830a
PS
2939 try {
2940 $DB->set_field_select($tablename, 'oneint', 'onestring', 'id = ?', array(1));
2941 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2942 } catch (moodle_exception $e) {
2943 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
2944 }
2945 try {
2946 $DB->set_field_select($tablename, 'onenum', 'onestring', 'id = ?', array(1));
2947 $this->fail("Expecting an exception, none occurred");
9d6d32b6
PS
2948 } catch (moodle_exception $e) {
2949 $this->assertInstanceOf('dml_exception', $e);
a3d5830a
PS
2950 }
2951
9d6d32b6 2952 // Check empty string data is stored as 0 in numeric datatypes.
a3d5830a
PS
2953 $DB->set_field_select($tablename, 'oneint', '', 'id = ?', array(1));
2954 $field = $DB->get_field($tablename, 'oneint', array('id' => 1));
2955 $this->assertTrue(is_numeric($field) && $field == 0);
2956
2957 $DB->set_field_select($tablename, 'onenum', '', 'id = ?', array(1));
2958 $field = $DB->get_field($tablename, 'onenum', array('id' => 1));
2959 $this->assertTrue(is_numeric($field) && $field == 0);
2960
9d6d32b6 2961 // Check empty strings are set properly in string types.
a3d5830a
PS
2962 $DB->set_field_select($tablename, 'onechar', '', 'id = ?', array(1));
2963 $DB->set_field_select($tablename, 'onetext', '', 'id = ?', array(1));
2964 $this->assertTrue($DB->get_field($tablename, 'onechar', array('id' => 1)) === '');
2965 $this->assertTrue($DB->get_field($tablename, 'onetext', array('id' => 1)) === '');
2966
9d6d32b6 2967 // Check operation ((210.10 + 39.92) - 150.02) against numeric types.
a3d5830a
PS
2968 $DB->set_field_select($tablename, 'oneint', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
2969 $DB->set_field_select($tablename, 'onenum', ((210.10 + 39.92) - 150.02), 'id = ?', array(1));
2970 $this->assertEquals(100, $DB->get_field($tablename, 'oneint', array('id' => 1)));
2971 $this->assertEquals(100, $DB->get_field($tablename, 'onenum', array('id' => 1)));
2972
9d6d32b6 2973 // Check various quotes/backslashes combinations in string types.
a3d5830a
PS
2974 $teststrings = array(
2975 'backslashes and quotes alone (even): "" \'\' \\\\',
2976 'backslashes and quotes alone (odd): """ \'\'\' \\\\\\',
2977 'backslashes and quotes sequences (even): \\"\\" \\\'\\\'',
2978 'backslashes and quotes sequences (odd): \\"\\"\\" \\\'\\\'\\\'');
2979 foreach ($teststrings as $teststring) {
2980 $DB->set_field_select($tablename, 'onechar', $teststring, 'id = ?', array(1));
2981 $DB->set_field_select($tablename, 'onetext', $teststring, 'id = ?', array(1));
2982 $this->assertEquals($teststring, $DB->get_field($tablename, 'onechar', array('id' => 1)));
2983 $this->assertEquals($teststring, $DB->get_field($tablename, 'onetext', array('id' => 1)));
2984 }
2985
9d6d32b6 2986 // Check LOBs in text/binary columns.
a3d5830a
PS
2987 $clob = file_get_contents(__DIR__ . '/fixtures/clob.txt');
2988 $blob = file_get_contents(__DIR__ . '/fixtures/randombinary');
2989 $DB->set_field_select($tablename, 'onetext', $clob, 'id = ?', array(1));
2990 $DB->set_field_select($tablename, 'onebinary', $blob, 'id = ?', array(1));
2991 $this->assertEquals($clob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test CLOB set_field (full contents output disabled)');
2992 $this->assertEquals($blob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test BLOB set_field (full contents output disabled)');
2993
9d6d32b6 2994 // And "small" LOBs too, just in case.
a3d5830a
PS
2995 $newclob = substr($clob, 0, 500);
2996 $newblob = substr($blob, 0, 250);
2997 $DB->set_field_select($tablename, 'onetext', $newclob, 'id = ?', array(1));
2998 $DB->set_field_select($tablename, 'onebinary', $newblob, 'id = ?', array(1));
2999 $this->assertEquals($newclob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test "small" CLOB set_field (full contents output disabled)');
3000 $this->assertEquals($newblob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test "small" BLOB set_field (full contents output disabled)');
3001
3002 // This is the failure from MDL-24863. This was giving an error on MSSQL,
3003 // which converts the '1' to an integer, which cannot then be compared with
3004 // onetext cast to a varchar. This should be fixed and working now.
3005 $newchar = 'frog';
9d6d32b6 3006 // Test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int).
a3d5830a
PS
3007 $params = array('onetext' => '1');
3008 try {
3009 $DB->set_field_select($tablename, 'onechar', $newchar, $DB->sql_compare_text('onetext') . ' = ?', $params);
3010 $this->assertTrue(true, 'No exceptions thrown with numerical text param comparison for text field.');
3011 } catch (dml_exception $e) {
3012 $this->assertFalse(true, 'We have an unexpected exception.');
3013 throw $e;
3014 }
a3d5830a
PS
3015 }
3016
3017 public function test_count_records() {
3018 $DB = $this->tdb;
3019
3020 $dbman = $DB->get_manager();
3021
3022 $table = $this->get_test_table();
3023 $tablename = $table->getName();
3024
9d6d32b6
PS
3025 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3026 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
3027 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
3028 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3029 $dbman->create_table($table);
3030
63224dee 3031 $this->assertSame(0, $DB->count_records($tablename));
a3d5830a
PS
3032
3033 $DB->insert_record($tablename, array('course' => 3));
3034 $DB->insert_record($tablename, array('course' => 4));
3035 $DB->insert_record($tablename, array('course' => 5));
3036
63224dee 3037 $this->assertSame(3, $DB->count_records($tablename));
a3d5830a 3038
9d6d32b6 3039 // Test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int).
a3d5830a
PS
3040 $conditions = array('onetext' => '1');
3041 try {
3042 $DB->count_records($tablename, $conditions);
3043 if (debugging()) {
9d6d32b6 3044 // Only in debug mode - hopefully all devs test code in debug mode...
a3d5830a
PS
3045 $this->fail('An Exception is missing, expected due to equating of text fields');
3046 }
9d6d32b6
PS
3047 } catch (moodle_exception $e) {
3048 $this->assertInstanceOf('dml_exception', $e);
3049 $this->assertSame('textconditionsnotallowed', $e->errorcode);
a3d5830a
PS
3050 }
3051 }
3052
3053 public function test_count_records_select() {
3054 $DB = $this->tdb;
3055
3056 $dbman = $DB->get_manager();
3057
3058 $table = $this->get_test_table();
3059 $tablename = $table->getName();
3060
9d6d32b6
PS
3061 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3062 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
3063 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3064 $dbman->create_table($table);
3065
63224dee 3066 $this->assertSame(0, $DB->count_records($tablename));
a3d5830a
PS
3067
3068 $DB->insert_record($tablename, array('course' => 3));
3069 $DB->insert_record($tablename, array('course' => 4));
3070 $DB->insert_record($tablename, array('course' => 5));
3071
63224dee 3072 $this->assertSame(2, $DB->count_records_select($tablename, 'course > ?', array(3)));
a3d5830a
PS
3073 }
3074
3075 public function test_count_records_sql() {
3076 $DB = $this->tdb;
3077 $dbman = $DB->get_manager();
3078
3079 $table = $this->get_test_table();
3080 $tablename = $table->getName();
3081
9d6d32b6
PS
3082 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3083 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
63224dee 3084 $table->add_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
a3d5830a
PS
3085 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3086 $dbman->create_table($table);
3087
63224dee 3088 $this->assertSame(0, $DB->count_records($tablename));
a3d5830a 3089
63224dee
PS
3090 $DB->insert_record($tablename, array('course' => 3, 'onechar' => 'a'));
3091 $DB->insert_record($tablename, array('course' => 4, 'onechar' => 'b'));
3092 $DB->insert_record($tablename, array('course' => 5, 'onechar' => 'c'));
3093
3094 $this->assertSame(2, $DB->count_records_sql("SELECT COUNT(*) FROM {{$tablename}} WHERE course > ?", array(3)));
a3d5830a 3095
9d6d32b6 3096 // Test invalid use.
63224dee
PS
3097 try {
3098 $DB->count_records_sql("SELECT onechar FROM {{$tablename}} WHERE course = ?", array(3));
3099 $this->fail('Exception expected when non-number field used in count_records_sql');
9d6d32b6 3100 } catch (moodle_exception $e) {
63224dee
PS
3101 $this->assertInstanceOf('coding_exception', $e);
3102 }
3103
3104 try {
3105 $DB->count_records_sql("SELECT course FROM {{$tablename}} WHERE 1 = 2");
3106 $this->fail('Exception expected when non-number field used in count_records_sql');
9d6d32b6 3107 } catch (moodle_exception $e) {
63224dee
PS
3108 $this->assertInstanceOf('coding_exception', $e);
3109 }
a3d5830a
PS
3110 }
3111
3112 public function test_record_exists() {
3113 $DB = $this->tdb;
3114 $dbman = $DB->get_manager();
3115
3116 $table = $this->get_test_table();
3117 $tablename = $table->getName();
3118
9d6d32b6
PS
3119 $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
3120 $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
a3d5830a
PS
3121 $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
3122 $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
3123 $dbman->create_table($table);
3124
3125 $this->assertEquals(0, $DB->count_records($tablename));
3126
3127 $this->assertFalse($DB->record_exists($tablename, array('course' => 3)));
3128 $DB->insert_record($tablename, array('course' => 3));
3129
3130 $this->assertTrue($DB->record_exists($tablename, array('course' => 3)));
3131
9d6d32b6 3132 // Test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int).
a3d5830a
PS
3133 $conditions = array('onetext' => '1');
3134 try {
3135 $DB->record_exists($tablename, $conditions);
3136 if (debugging()) {
9d6d32b6 3137 // Only in debug mode - hopefully all devs test code in debug mode...
a3d5830a
PS
3138 $this->fail('An Exception is missing, expected due to equating of text fields');
3139