PageRenderTime 52ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 2ms

/lib/dml/tests/dml_test.php

https://bitbucket.org/synergylearning/campusconnect
PHP | 5130 lines | 4233 code | 608 blank | 289 comment | 39 complexity | 3adb6d4d0af7ac967f14386888f437a4 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, LGPL-2.1, Apache-2.0, BSD-3-Clause, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  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. * DML layer tests.
  18. *
  19. * @package core_dml
  20. * @category phpunit
  21. * @copyright 2008 Nicolas Connault
  22. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23. */
  24. defined('MOODLE_INTERNAL') || die();
  25. class core_dml_testcase extends database_driver_testcase {
  26. protected function setUp() {
  27. parent::setUp();
  28. $dbman = $this->tdb->get_manager(); // Loads DDL libs.
  29. }
  30. /**
  31. * Get a xmldb_table object for testing, deleting any existing table
  32. * of the same name, for example if one was left over from a previous test
  33. * run that crashed.
  34. *
  35. * @param string $suffix table name suffix, use if you need more test tables
  36. * @return xmldb_table the table object.
  37. */
  38. private function get_test_table($suffix = '') {
  39. $tablename = "test_table";
  40. if ($suffix !== '') {
  41. $tablename .= $suffix;
  42. }
  43. $table = new xmldb_table($tablename);
  44. $table->setComment("This is a test'n drop table. You can drop it safely");
  45. return new xmldb_table($tablename);
  46. }
  47. public function test_diagnose() {
  48. $DB = $this->tdb;
  49. $result = $DB->diagnose();
  50. $this->assertNull($result, 'Database self diagnostics failed %s');
  51. }
  52. public function test_get_server_info() {
  53. $DB = $this->tdb;
  54. $result = $DB->get_server_info();
  55. $this->assertInternalType('array', $result);
  56. $this->assertArrayHasKey('description', $result);
  57. $this->assertArrayHasKey('version', $result);
  58. }
  59. public function test_get_in_or_equal() {
  60. $DB = $this->tdb;
  61. // SQL_PARAMS_QM - IN or =.
  62. // Correct usage of multiple values.
  63. $in_values = array('value1', 'value2', '3', 4, null, false, true);
  64. list($usql, $params) = $DB->get_in_or_equal($in_values);
  65. $this->assertSame('IN ('.implode(',', array_fill(0, count($in_values), '?')).')', $usql);
  66. $this->assertEquals(count($in_values), count($params));
  67. foreach ($params as $key => $value) {
  68. $this->assertSame($in_values[$key], $value);
  69. }
  70. // Correct usage of single value (in an array).
  71. $in_values = array('value1');
  72. list($usql, $params) = $DB->get_in_or_equal($in_values);
  73. $this->assertEquals("= ?", $usql);
  74. $this->assertCount(1, $params);
  75. $this->assertEquals($in_values[0], $params[0]);
  76. // Correct usage of single value.
  77. $in_value = 'value1';
  78. list($usql, $params) = $DB->get_in_or_equal($in_values);
  79. $this->assertEquals("= ?", $usql);
  80. $this->assertCount(1, $params);
  81. $this->assertEquals($in_value, $params[0]);
  82. // SQL_PARAMS_QM - NOT IN or <>.
  83. // Correct usage of multiple values.
  84. $in_values = array('value1', 'value2', 'value3', 'value4');
  85. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
  86. $this->assertEquals("NOT IN (?,?,?,?)", $usql);
  87. $this->assertCount(4, $params);
  88. foreach ($params as $key => $value) {
  89. $this->assertEquals($in_values[$key], $value);
  90. }
  91. // Correct usage of single value (in array().
  92. $in_values = array('value1');
  93. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
  94. $this->assertEquals("<> ?", $usql);
  95. $this->assertCount(1, $params);
  96. $this->assertEquals($in_values[0], $params[0]);
  97. // Correct usage of single value.
  98. $in_value = 'value1';
  99. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, null, false);
  100. $this->assertEquals("<> ?", $usql);
  101. $this->assertCount(1, $params);
  102. $this->assertEquals($in_value, $params[0]);
  103. // SQL_PARAMS_NAMED - IN or =.
  104. // Correct usage of multiple values.
  105. $in_values = array('value1', 'value2', 'value3', 'value4');
  106. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
  107. $this->assertCount(4, $params);
  108. reset($in_values);
  109. $ps = array();
  110. foreach ($params as $key => $value) {
  111. $this->assertEquals(current($in_values), $value);
  112. next($in_values);
  113. $ps[] = ':'.$key;
  114. }
  115. $this->assertEquals("IN (".implode(',', $ps).")", $usql);
  116. // Correct usage of single values (in array).
  117. $in_values = array('value1');
  118. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
  119. $this->assertCount(1, $params);
  120. $value = reset($params);
  121. $key = key($params);
  122. $this->assertEquals("= :$key", $usql);
  123. $this->assertEquals($in_value, $value);
  124. // Correct usage of single value.
  125. $in_value = 'value1';
  126. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', true);
  127. $this->assertCount(1, $params);
  128. $value = reset($params);
  129. $key = key($params);
  130. $this->assertEquals("= :$key", $usql);
  131. $this->assertEquals($in_value, $value);
  132. // SQL_PARAMS_NAMED - NOT IN or <>.
  133. // Correct usage of multiple values.
  134. $in_values = array('value1', 'value2', 'value3', 'value4');
  135. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
  136. $this->assertCount(4, $params);
  137. reset($in_values);
  138. $ps = array();
  139. foreach ($params as $key => $value) {
  140. $this->assertEquals(current($in_values), $value);
  141. next($in_values);
  142. $ps[] = ':'.$key;
  143. }
  144. $this->assertEquals("NOT IN (".implode(',', $ps).")", $usql);
  145. // Correct usage of single values (in array).
  146. $in_values = array('value1');
  147. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
  148. $this->assertCount(1, $params);
  149. $value = reset($params);
  150. $key = key($params);
  151. $this->assertEquals("<> :$key", $usql);
  152. $this->assertEquals($in_value, $value);
  153. // Correct usage of single value.
  154. $in_value = 'value1';
  155. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
  156. $this->assertCount(1, $params);
  157. $value = reset($params);
  158. $key = key($params);
  159. $this->assertEquals("<> :$key", $usql);
  160. $this->assertEquals($in_value, $value);
  161. // Make sure the param names are unique.
  162. list($usql1, $params1) = $DB->get_in_or_equal(array(1, 2, 3), SQL_PARAMS_NAMED, 'param');
  163. list($usql2, $params2) = $DB->get_in_or_equal(array(1, 2, 3), SQL_PARAMS_NAMED, 'param');
  164. $params1 = array_keys($params1);
  165. $params2 = array_keys($params2);
  166. $common = array_intersect($params1, $params2);
  167. $this->assertCount(0, $common);
  168. // Some incorrect tests.
  169. // Incorrect usage passing not-allowed params type.
  170. $in_values = array(1, 2, 3);
  171. try {
  172. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_DOLLAR, 'param', false);
  173. $this->fail('An Exception is missing, expected due to not supported SQL_PARAMS_DOLLAR');
  174. } catch (moodle_exception $e) {
  175. $this->assertInstanceOf('dml_exception', $e);
  176. $this->assertSame('typenotimplement', $e->errorcode);
  177. }
  178. // Incorrect usage passing empty array.
  179. $in_values = array();
  180. try {
  181. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false);
  182. $this->fail('An Exception is missing, expected due to empty array of items');
  183. } catch (moodle_exception $e) {
  184. $this->assertInstanceOf('coding_exception', $e);
  185. }
  186. // Test using $onemptyitems.
  187. // Correct usage passing empty array and $onemptyitems = null (equal = true, QM).
  188. $in_values = array();
  189. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, null);
  190. $this->assertSame(' IS NULL', $usql);
  191. $this->assertSame(array(), $params);
  192. // Correct usage passing empty array and $onemptyitems = null (equal = false, NAMED).
  193. $in_values = array();
  194. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, null);
  195. $this->assertSame(' IS NOT NULL', $usql);
  196. $this->assertSame(array(), $params);
  197. // Correct usage passing empty array and $onemptyitems = true (equal = true, QM).
  198. $in_values = array();
  199. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, true);
  200. $this->assertSame('= ?', $usql);
  201. $this->assertSame(array(true), $params);
  202. // Correct usage passing empty array and $onemptyitems = true (equal = false, NAMED).
  203. $in_values = array();
  204. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, true);
  205. $this->assertCount(1, $params);
  206. $value = reset($params);
  207. $key = key($params);
  208. $this->assertSame('<> :'.$key, $usql);
  209. $this->assertSame($value, true);
  210. // Correct usage passing empty array and $onemptyitems = -1 (equal = true, QM).
  211. $in_values = array();
  212. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, -1);
  213. $this->assertSame('= ?', $usql);
  214. $this->assertSame(array(-1), $params);
  215. // Correct usage passing empty array and $onemptyitems = -1 (equal = false, NAMED).
  216. $in_values = array();
  217. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, -1);
  218. $this->assertCount(1, $params);
  219. $value = reset($params);
  220. $key = key($params);
  221. $this->assertSame('<> :'.$key, $usql);
  222. $this->assertSame($value, -1);
  223. // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = true, QM).
  224. $in_values = array();
  225. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_QM, 'param', true, 'onevalue');
  226. $this->assertSame('= ?', $usql);
  227. $this->assertSame(array('onevalue'), $params);
  228. // Correct usage passing empty array and $onemptyitems = 'onevalue' (equal = false, NAMED).
  229. $in_values = array();
  230. list($usql, $params) = $DB->get_in_or_equal($in_values, SQL_PARAMS_NAMED, 'param', false, 'onevalue');
  231. $this->assertCount(1, $params);
  232. $value = reset($params);
  233. $key = key($params);
  234. $this->assertSame('<> :'.$key, $usql);
  235. $this->assertSame($value, 'onevalue');
  236. }
  237. public function test_fix_table_names() {
  238. $DB = new moodle_database_for_testing();
  239. $prefix = $DB->get_prefix();
  240. // Simple placeholder.
  241. $placeholder = "{user_123}";
  242. $this->assertSame($prefix."user_123", $DB->public_fix_table_names($placeholder));
  243. // Wrong table name.
  244. $placeholder = "{user-a}";
  245. $this->assertSame($placeholder, $DB->public_fix_table_names($placeholder));
  246. // Wrong table name.
  247. $placeholder = "{123user}";
  248. $this->assertSame($placeholder, $DB->public_fix_table_names($placeholder));
  249. // Full SQL.
  250. $sql = "SELECT * FROM {user}, {funny_table_name}, {mdl_stupid_table} WHERE {user}.id = {funny_table_name}.userid";
  251. $expected = "SELECT * FROM {$prefix}user, {$prefix}funny_table_name, {$prefix}mdl_stupid_table WHERE {$prefix}user.id = {$prefix}funny_table_name.userid";
  252. $this->assertSame($expected, $DB->public_fix_table_names($sql));
  253. }
  254. public function test_fix_sql_params() {
  255. $DB = $this->tdb;
  256. $prefix = $DB->get_prefix();
  257. $table = $this->get_test_table();
  258. $tablename = $table->getName();
  259. // Correct table placeholder substitution.
  260. $sql = "SELECT * FROM {{$tablename}}";
  261. $sqlarray = $DB->fix_sql_params($sql);
  262. $this->assertEquals("SELECT * FROM {$prefix}".$tablename, $sqlarray[0]);
  263. // Conversions of all param types.
  264. $sql = array();
  265. $sql[SQL_PARAMS_NAMED] = "SELECT * FROM {$prefix}testtable WHERE name = :param1, course = :param2";
  266. $sql[SQL_PARAMS_QM] = "SELECT * FROM {$prefix}testtable WHERE name = ?, course = ?";
  267. $sql[SQL_PARAMS_DOLLAR] = "SELECT * FROM {$prefix}testtable WHERE name = \$1, course = \$2";
  268. $params = array();
  269. $params[SQL_PARAMS_NAMED] = array('param1'=>'first record', 'param2'=>1);
  270. $params[SQL_PARAMS_QM] = array('first record', 1);
  271. $params[SQL_PARAMS_DOLLAR] = array('first record', 1);
  272. list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_NAMED], $params[SQL_PARAMS_NAMED]);
  273. $this->assertSame($rsql, $sql[$rtype]);
  274. $this->assertSame($rparams, $params[$rtype]);
  275. list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_QM], $params[SQL_PARAMS_QM]);
  276. $this->assertSame($rsql, $sql[$rtype]);
  277. $this->assertSame($rparams, $params[$rtype]);
  278. list($rsql, $rparams, $rtype) = $DB->fix_sql_params($sql[SQL_PARAMS_DOLLAR], $params[SQL_PARAMS_DOLLAR]);
  279. $this->assertSame($rsql, $sql[$rtype]);
  280. $this->assertSame($rparams, $params[$rtype]);
  281. // Malformed table placeholder.
  282. $sql = "SELECT * FROM [testtable]";
  283. $sqlarray = $DB->fix_sql_params($sql);
  284. $this->assertSame($sql, $sqlarray[0]);
  285. // Mixed param types (colon and dollar).
  286. $sql = "SELECT * FROM {{$tablename}} WHERE name = :param1, course = \$1";
  287. $params = array('param1' => 'record1', 'param2' => 3);
  288. try {
  289. $DB->fix_sql_params($sql, $params);
  290. $this->fail("Expecting an exception, none occurred");
  291. } catch (moodle_exception $e) {
  292. $this->assertInstanceOf('dml_exception', $e);
  293. }
  294. // Mixed param types (question and dollar).
  295. $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = \$1";
  296. $params = array('param1' => 'record2', 'param2' => 5);
  297. try {
  298. $DB->fix_sql_params($sql, $params);
  299. $this->fail("Expecting an exception, none occurred");
  300. } catch (moodle_exception $e) {
  301. $this->assertInstanceOf('dml_exception', $e);
  302. }
  303. // Too few params in sql.
  304. $sql = "SELECT * FROM {{$tablename}} WHERE name = ?, course = ?, id = ?";
  305. $params = array('record2', 3);
  306. try {
  307. $DB->fix_sql_params($sql, $params);
  308. $this->fail("Expecting an exception, none occurred");
  309. } catch (moodle_exception $e) {
  310. $this->assertInstanceOf('dml_exception', $e);
  311. }
  312. // Too many params in array: no error, just use what is necessary.
  313. $params[] = 1;
  314. $params[] = time();
  315. $sqlarray = $DB->fix_sql_params($sql, $params);
  316. $this->assertInternalType('array', $sqlarray);
  317. $this->assertCount(3, $sqlarray[1]);
  318. // Named params missing from array.
  319. $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
  320. $params = array('wrongname' => 'record1', 'course' => 1);
  321. try {
  322. $DB->fix_sql_params($sql, $params);
  323. $this->fail("Expecting an exception, none occurred");
  324. } catch (moodle_exception $e) {
  325. $this->assertInstanceOf('dml_exception', $e);
  326. }
  327. // Duplicate named param in query - this is a very important feature!!
  328. // it helps with debugging of sloppy code.
  329. $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :name";
  330. $params = array('name' => 'record2', 'course' => 3);
  331. try {
  332. $DB->fix_sql_params($sql, $params);
  333. $this->fail("Expecting an exception, none occurred");
  334. } catch (moodle_exception $e) {
  335. $this->assertInstanceOf('dml_exception', $e);
  336. }
  337. // Extra named param is ignored.
  338. $sql = "SELECT * FROM {{$tablename}} WHERE name = :name, course = :course";
  339. $params = array('name' => 'record1', 'course' => 1, 'extrastuff'=>'haha');
  340. $sqlarray = $DB->fix_sql_params($sql, $params);
  341. $this->assertInternalType('array', $sqlarray);
  342. $this->assertCount(2, $sqlarray[1]);
  343. // Params exceeding 30 chars length.
  344. $sql = "SELECT * FROM {{$tablename}} WHERE name = :long_placeholder_with_more_than_30";
  345. $params = array('long_placeholder_with_more_than_30' => 'record1');
  346. try {
  347. $DB->fix_sql_params($sql, $params);
  348. $this->fail("Expecting an exception, none occurred");
  349. } catch (moodle_exception $e) {
  350. $this->assertInstanceOf('coding_exception', $e);
  351. }
  352. // Booleans in NAMED params are casting to 1/0 int.
  353. $sql = "SELECT * FROM {{$tablename}} WHERE course = ? OR course = ?";
  354. $params = array(true, false);
  355. list($sql, $params) = $DB->fix_sql_params($sql, $params);
  356. $this->assertTrue(reset($params) === 1);
  357. $this->assertTrue(next($params) === 0);
  358. // Booleans in QM params are casting to 1/0 int.
  359. $sql = "SELECT * FROM {{$tablename}} WHERE course = :course1 OR course = :course2";
  360. $params = array('course1' => true, 'course2' => false);
  361. list($sql, $params) = $DB->fix_sql_params($sql, $params);
  362. $this->assertTrue(reset($params) === 1);
  363. $this->assertTrue(next($params) === 0);
  364. // Booleans in DOLLAR params are casting to 1/0 int.
  365. $sql = "SELECT * FROM {{$tablename}} WHERE course = \$1 OR course = \$2";
  366. $params = array(true, false);
  367. list($sql, $params) = $DB->fix_sql_params($sql, $params);
  368. $this->assertTrue(reset($params) === 1);
  369. $this->assertTrue(next($params) === 0);
  370. // No data types are touched except bool.
  371. $sql = "SELECT * FROM {{$tablename}} WHERE name IN (?,?,?,?,?,?)";
  372. $inparams = array('abc', 'ABC', null, '1', 1, 1.4);
  373. list($sql, $params) = $DB->fix_sql_params($sql, $inparams);
  374. $this->assertSame(array_values($params), array_values($inparams));
  375. }
  376. public function test_strtok() {
  377. // Strtok was previously used by bound emulation, make sure it is not used any more.
  378. $DB = $this->tdb;
  379. $dbman = $this->tdb->get_manager();
  380. $table = $this->get_test_table();
  381. $tablename = $table->getName();
  382. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  383. $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  384. $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
  385. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  386. $dbman->create_table($table);
  387. $str = 'a?b?c?d';
  388. $this->assertSame(strtok($str, '?'), 'a');
  389. $DB->get_records($tablename, array('id'=>1));
  390. $this->assertSame(strtok('?'), 'b');
  391. }
  392. public function test_tweak_param_names() {
  393. // Note the tweak_param_names() method is only available in the oracle driver,
  394. // hence we look for expected results indirectly, by testing various DML methods.
  395. // with some "extreme" conditions causing the tweak to happen.
  396. $DB = $this->tdb;
  397. $dbman = $this->tdb->get_manager();
  398. $table = $this->get_test_table();
  399. $tablename = $table->getName();
  400. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  401. // Add some columns with 28 chars in the name.
  402. $table->add_field('long_int_columnname_with_28c', XMLDB_TYPE_INTEGER, '10');
  403. $table->add_field('long_dec_columnname_with_28c', XMLDB_TYPE_NUMBER, '10,2');
  404. $table->add_field('long_str_columnname_with_28c', XMLDB_TYPE_CHAR, '100');
  405. // Add some columns with 30 chars in the name.
  406. $table->add_field('long_int_columnname_with_30cxx', XMLDB_TYPE_INTEGER, '10');
  407. $table->add_field('long_dec_columnname_with_30cxx', XMLDB_TYPE_NUMBER, '10,2');
  408. $table->add_field('long_str_columnname_with_30cxx', XMLDB_TYPE_CHAR, '100');
  409. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  410. $dbman->create_table($table);
  411. $this->assertTrue($dbman->table_exists($tablename));
  412. // Test insert record.
  413. $rec1 = new stdClass();
  414. $rec1->long_int_columnname_with_28c = 28;
  415. $rec1->long_dec_columnname_with_28c = 28.28;
  416. $rec1->long_str_columnname_with_28c = '28';
  417. $rec1->long_int_columnname_with_30cxx = 30;
  418. $rec1->long_dec_columnname_with_30cxx = 30.30;
  419. $rec1->long_str_columnname_with_30cxx = '30';
  420. // Insert_record().
  421. $rec1->id = $DB->insert_record($tablename, $rec1);
  422. $this->assertEquals($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
  423. // Update_record().
  424. $DB->update_record($tablename, $rec1);
  425. $this->assertEquals($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
  426. // Set_field().
  427. $rec1->long_int_columnname_with_28c = 280;
  428. $DB->set_field($tablename, 'long_int_columnname_with_28c', $rec1->long_int_columnname_with_28c,
  429. array('id' => $rec1->id, 'long_int_columnname_with_28c' => 28));
  430. $rec1->long_dec_columnname_with_28c = 280.28;
  431. $DB->set_field($tablename, 'long_dec_columnname_with_28c', $rec1->long_dec_columnname_with_28c,
  432. array('id' => $rec1->id, 'long_dec_columnname_with_28c' => 28.28));
  433. $rec1->long_str_columnname_with_28c = '280';
  434. $DB->set_field($tablename, 'long_str_columnname_with_28c', $rec1->long_str_columnname_with_28c,
  435. array('id' => $rec1->id, 'long_str_columnname_with_28c' => '28'));
  436. $rec1->long_int_columnname_with_30cxx = 300;
  437. $DB->set_field($tablename, 'long_int_columnname_with_30cxx', $rec1->long_int_columnname_with_30cxx,
  438. array('id' => $rec1->id, 'long_int_columnname_with_30cxx' => 30));
  439. $rec1->long_dec_columnname_with_30cxx = 300.30;
  440. $DB->set_field($tablename, 'long_dec_columnname_with_30cxx', $rec1->long_dec_columnname_with_30cxx,
  441. array('id' => $rec1->id, 'long_dec_columnname_with_30cxx' => 30.30));
  442. $rec1->long_str_columnname_with_30cxx = '300';
  443. $DB->set_field($tablename, 'long_str_columnname_with_30cxx', $rec1->long_str_columnname_with_30cxx,
  444. array('id' => $rec1->id, 'long_str_columnname_with_30cxx' => '30'));
  445. $this->assertEquals($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
  446. // Delete_records().
  447. $rec2 = $DB->get_record($tablename, array('id' => $rec1->id));
  448. $rec2->id = $DB->insert_record($tablename, $rec2);
  449. $this->assertEquals(2, $DB->count_records($tablename));
  450. $DB->delete_records($tablename, (array) $rec2);
  451. $this->assertEquals(1, $DB->count_records($tablename));
  452. // Get_recordset().
  453. $rs = $DB->get_recordset($tablename, (array) $rec1);
  454. $iterations = 0;
  455. foreach ($rs as $rec2) {
  456. $iterations++;
  457. }
  458. $rs->close();
  459. $this->assertEquals(1, $iterations);
  460. $this->assertEquals($rec1, $rec2);
  461. // Get_records().
  462. $recs = $DB->get_records($tablename, (array) $rec1);
  463. $this->assertCount(1, $recs);
  464. $this->assertEquals($rec1, reset($recs));
  465. // Get_fieldset_select().
  466. $select = 'id = :id AND
  467. long_int_columnname_with_28c = :long_int_columnname_with_28c AND
  468. long_dec_columnname_with_28c = :long_dec_columnname_with_28c AND
  469. long_str_columnname_with_28c = :long_str_columnname_with_28c AND
  470. long_int_columnname_with_30cxx = :long_int_columnname_with_30cxx AND
  471. long_dec_columnname_with_30cxx = :long_dec_columnname_with_30cxx AND
  472. long_str_columnname_with_30cxx = :long_str_columnname_with_30cxx';
  473. $fields = $DB->get_fieldset_select($tablename, 'long_int_columnname_with_28c', $select, (array)$rec1);
  474. $this->assertCount(1, $fields);
  475. $this->assertEquals($rec1->long_int_columnname_with_28c, reset($fields));
  476. $fields = $DB->get_fieldset_select($tablename, 'long_dec_columnname_with_28c', $select, (array)$rec1);
  477. $this->assertEquals($rec1->long_dec_columnname_with_28c, reset($fields));
  478. $fields = $DB->get_fieldset_select($tablename, 'long_str_columnname_with_28c', $select, (array)$rec1);
  479. $this->assertEquals($rec1->long_str_columnname_with_28c, reset($fields));
  480. $fields = $DB->get_fieldset_select($tablename, 'long_int_columnname_with_30cxx', $select, (array)$rec1);
  481. $this->assertEquals($rec1->long_int_columnname_with_30cxx, reset($fields));
  482. $fields = $DB->get_fieldset_select($tablename, 'long_dec_columnname_with_30cxx', $select, (array)$rec1);
  483. $this->assertEquals($rec1->long_dec_columnname_with_30cxx, reset($fields));
  484. $fields = $DB->get_fieldset_select($tablename, 'long_str_columnname_with_30cxx', $select, (array)$rec1);
  485. $this->assertEquals($rec1->long_str_columnname_with_30cxx, reset($fields));
  486. // Overlapping placeholders (progressive str_replace).
  487. $overlapselect = 'id = :p AND
  488. long_int_columnname_with_28c = :param1 AND
  489. long_dec_columnname_with_28c = :param2 AND
  490. long_str_columnname_with_28c = :param_with_29_characters_long AND
  491. long_int_columnname_with_30cxx = :param_with_30_characters_long_ AND
  492. long_dec_columnname_with_30cxx = :param_ AND
  493. long_str_columnname_with_30cxx = :param__';
  494. $overlapparams = array(
  495. 'p' => $rec1->id,
  496. 'param1' => $rec1->long_int_columnname_with_28c,
  497. 'param2' => $rec1->long_dec_columnname_with_28c,
  498. 'param_with_29_characters_long' => $rec1->long_str_columnname_with_28c,
  499. 'param_with_30_characters_long_' => $rec1->long_int_columnname_with_30cxx,
  500. 'param_' => $rec1->long_dec_columnname_with_30cxx,
  501. 'param__' => $rec1->long_str_columnname_with_30cxx);
  502. $recs = $DB->get_records_select($tablename, $overlapselect, $overlapparams);
  503. $this->assertCount(1, $recs);
  504. $this->assertEquals($rec1, reset($recs));
  505. // Execute().
  506. $DB->execute("DELETE FROM {{$tablename}} WHERE $select", (array)$rec1);
  507. $this->assertEquals(0, $DB->count_records($tablename));
  508. }
  509. public function test_get_tables() {
  510. $DB = $this->tdb;
  511. $dbman = $this->tdb->get_manager();
  512. // Need to test with multiple DBs.
  513. $table = $this->get_test_table();
  514. $tablename = $table->getName();
  515. $original_count = count($DB->get_tables());
  516. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  517. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  518. $dbman->create_table($table);
  519. $this->assertTrue(count($DB->get_tables()) == $original_count + 1);
  520. $dbman->drop_table($table);
  521. $this->assertTrue(count($DB->get_tables()) == $original_count);
  522. }
  523. public function test_get_indexes() {
  524. $DB = $this->tdb;
  525. $dbman = $this->tdb->get_manager();
  526. $table = $this->get_test_table();
  527. $tablename = $table->getName();
  528. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  529. $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  530. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  531. $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
  532. $table->add_index('course-id', XMLDB_INDEX_UNIQUE, array('course', 'id'));
  533. $dbman->create_table($table);
  534. $indices = $DB->get_indexes($tablename);
  535. $this->assertInternalType('array', $indices);
  536. $this->assertCount(2, $indices);
  537. // We do not care about index names for now.
  538. $first = array_shift($indices);
  539. $second = array_shift($indices);
  540. if (count($first['columns']) == 2) {
  541. $composed = $first;
  542. $single = $second;
  543. } else {
  544. $composed = $second;
  545. $single = $first;
  546. }
  547. $this->assertFalse($single['unique']);
  548. $this->assertTrue($composed['unique']);
  549. $this->assertCount(1, $single['columns']);
  550. $this->assertCount(2, $composed['columns']);
  551. $this->assertSame('course', $single['columns'][0]);
  552. $this->assertSame('course', $composed['columns'][0]);
  553. $this->assertSame('id', $composed['columns'][1]);
  554. }
  555. public function test_get_columns() {
  556. $DB = $this->tdb;
  557. $dbman = $this->tdb->get_manager();
  558. $table = $this->get_test_table();
  559. $tablename = $table->getName();
  560. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  561. $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  562. $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
  563. $table->add_field('description', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
  564. $table->add_field('enumfield', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'test2');
  565. $table->add_field('onenum', XMLDB_TYPE_NUMBER, '10,2', null, null, null, 200);
  566. $table->add_field('onefloat', XMLDB_TYPE_FLOAT, '10,2', null, null, null, 300);
  567. $table->add_field('anotherfloat', XMLDB_TYPE_FLOAT, null, null, null, null, 400);
  568. $table->add_field('negativedfltint', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '-1');
  569. $table->add_field('negativedfltnumber', XMLDB_TYPE_NUMBER, '10', null, XMLDB_NOTNULL, null, '-2');
  570. $table->add_field('negativedfltfloat', XMLDB_TYPE_FLOAT, '10', null, XMLDB_NOTNULL, null, '-3');
  571. $table->add_field('someint1', XMLDB_TYPE_INTEGER, '1', null, null, null, '0');
  572. $table->add_field('someint2', XMLDB_TYPE_INTEGER, '2', null, null, null, '0');
  573. $table->add_field('someint3', XMLDB_TYPE_INTEGER, '3', null, null, null, '0');
  574. $table->add_field('someint4', XMLDB_TYPE_INTEGER, '4', null, null, null, '0');
  575. $table->add_field('someint5', XMLDB_TYPE_INTEGER, '5', null, null, null, '0');
  576. $table->add_field('someint6', XMLDB_TYPE_INTEGER, '6', null, null, null, '0');
  577. $table->add_field('someint7', XMLDB_TYPE_INTEGER, '7', null, null, null, '0');
  578. $table->add_field('someint8', XMLDB_TYPE_INTEGER, '8', null, null, null, '0');
  579. $table->add_field('someint9', XMLDB_TYPE_INTEGER, '9', null, null, null, '0');
  580. $table->add_field('someint10', XMLDB_TYPE_INTEGER, '10', null, null, null, '0');
  581. $table->add_field('someint18', XMLDB_TYPE_INTEGER, '18', null, null, null, '0');
  582. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  583. $dbman->create_table($table);
  584. $columns = $DB->get_columns($tablename);
  585. $this->assertInternalType('array', $columns);
  586. $fields = $table->getFields();
  587. $this->assertCount(count($columns), $fields);
  588. $field = $columns['id'];
  589. $this->assertSame('R', $field->meta_type);
  590. $this->assertTrue($field->auto_increment);
  591. $this->assertTrue($field->unique);
  592. $field = $columns['course'];
  593. $this->assertSame('I', $field->meta_type);
  594. $this->assertFalse($field->auto_increment);
  595. $this->assertTrue($field->has_default);
  596. $this->assertEquals(0, $field->default_value);
  597. $this->assertTrue($field->not_null);
  598. for ($i=1; $i<=10; $i++) {
  599. $field = $columns['someint'.$i];
  600. $this->assertSame('I', $field->meta_type);
  601. $this->assertGreaterThanOrEqual($i, $field->max_length);
  602. }
  603. $field = $columns['someint18'];
  604. $this->assertSame('I', $field->meta_type);
  605. $this->assertGreaterThanOrEqual(18, $field->max_length);
  606. $field = $columns['name'];
  607. $this->assertSame('C', $field->meta_type);
  608. $this->assertFalse($field->auto_increment);
  609. $this->assertEquals(255, $field->max_length);
  610. $this->assertTrue($field->has_default);
  611. $this->assertSame('lala', $field->default_value);
  612. $this->assertFalse($field->not_null);
  613. $field = $columns['description'];
  614. $this->assertSame('X', $field->meta_type);
  615. $this->assertFalse($field->auto_increment);
  616. $this->assertFalse($field->has_default);
  617. $this->assertNull($field->default_value);
  618. $this->assertFalse($field->not_null);
  619. $field = $columns['enumfield'];
  620. $this->assertSame('C', $field->meta_type);
  621. $this->assertFalse($field->auto_increment);
  622. $this->assertSame('test2', $field->default_value);
  623. $this->assertTrue($field->not_null);
  624. $field = $columns['onenum'];
  625. $this->assertSame('N', $field->meta_type);
  626. $this->assertFalse($field->auto_increment);
  627. $this->assertEquals(10, $field->max_length);
  628. $this->assertEquals(2, $field->scale);
  629. $this->assertTrue($field->has_default);
  630. $this->assertEquals(200.0, $field->default_value);
  631. $this->assertFalse($field->not_null);
  632. $field = $columns['onefloat'];
  633. $this->assertSame('N', $field->meta_type);
  634. $this->assertFalse($field->auto_increment);
  635. $this->assertTrue($field->has_default);
  636. $this->assertEquals(300.0, $field->default_value);
  637. $this->assertFalse($field->not_null);
  638. $field = $columns['anotherfloat'];
  639. $this->assertSame('N', $field->meta_type);
  640. $this->assertFalse($field->auto_increment);
  641. $this->assertTrue($field->has_default);
  642. $this->assertEquals(400.0, $field->default_value);
  643. $this->assertFalse($field->not_null);
  644. // Test negative defaults in numerical columns.
  645. $field = $columns['negativedfltint'];
  646. $this->assertTrue($field->has_default);
  647. $this->assertEquals(-1, $field->default_value);
  648. $field = $columns['negativedfltnumber'];
  649. $this->assertTrue($field->has_default);
  650. $this->assertEquals(-2, $field->default_value);
  651. $field = $columns['negativedfltfloat'];
  652. $this->assertTrue($field->has_default);
  653. $this->assertEquals(-3, $field->default_value);
  654. for ($i = 0; $i < count($columns); $i++) {
  655. if ($i == 0) {
  656. $next_column = reset($columns);
  657. $next_field = reset($fields);
  658. } else {
  659. $next_column = next($columns);
  660. $next_field = next($fields);
  661. }
  662. $this->assertEquals($next_column->name, $next_field->getName());
  663. }
  664. // Test get_columns for non-existing table returns empty array. MDL-30147.
  665. $columns = $DB->get_columns('xxxx');
  666. $this->assertEquals(array(), $columns);
  667. // Create something similar to "context_temp" with id column without sequence.
  668. $dbman->drop_table($table);
  669. $table = $this->get_test_table();
  670. $tablename = $table->getName();
  671. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
  672. $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  673. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  674. $dbman->create_table($table);
  675. $columns = $DB->get_columns($tablename);
  676. $this->assertFalse($columns['id']->auto_increment);
  677. }
  678. public function test_get_manager() {
  679. $DB = $this->tdb;
  680. $dbman = $this->tdb->get_manager();
  681. $this->assertInstanceOf('database_manager', $dbman);
  682. }
  683. public function test_setup_is_unicodedb() {
  684. $DB = $this->tdb;
  685. $this->assertTrue($DB->setup_is_unicodedb());
  686. }
  687. public function test_set_debug() { // Tests get_debug() too.
  688. $DB = $this->tdb;
  689. $dbman = $this->tdb->get_manager();
  690. $table = $this->get_test_table();
  691. $tablename = $table->getName();
  692. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  693. $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  694. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  695. $dbman->create_table($table);
  696. $sql = "SELECT * FROM {{$tablename}}";
  697. $prevdebug = $DB->get_debug();
  698. ob_start();
  699. $DB->set_debug(true);
  700. $this->assertTrue($DB->get_debug());
  701. $DB->execute($sql);
  702. $DB->set_debug(false);
  703. $this->assertFalse($DB->get_debug());
  704. $debuginfo = ob_get_contents();
  705. ob_end_clean();
  706. $this->assertFalse($debuginfo === '');
  707. ob_start();
  708. $DB->execute($sql);
  709. $debuginfo = ob_get_contents();
  710. ob_end_clean();
  711. $this->assertTrue($debuginfo === '');
  712. $DB->set_debug($prevdebug);
  713. }
  714. public function test_execute() {
  715. $DB = $this->tdb;
  716. $dbman = $this->tdb->get_manager();
  717. $table1 = $this->get_test_table('1');
  718. $tablename1 = $table1->getName();
  719. $table1->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  720. $table1->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  721. $table1->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
  722. $table1->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
  723. $table1->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  724. $dbman->create_table($table1);
  725. $table2 = $this->get_test_table('2');
  726. $tablename2 = $table2->getName();
  727. $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  728. $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  729. $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  730. $dbman->create_table($table2);
  731. $DB->insert_record($tablename1, array('course' => 3, 'name' => 'aaa'));
  732. $DB->insert_record($tablename1, array('course' => 1, 'name' => 'bbb'));
  733. $DB->insert_record($tablename1, array('course' => 7, 'name' => 'ccc'));
  734. $DB->insert_record($tablename1, array('course' => 3, 'name' => 'ddd'));
  735. // Select results are ignored.
  736. $sql = "SELECT * FROM {{$tablename1}} WHERE course = :course";
  737. $this->assertTrue($DB->execute($sql, array('course'=>3)));
  738. // Throw exception on error.
  739. $sql = "XXUPDATE SET XSSD";
  740. try {
  741. $DB->execute($sql);
  742. $this->fail("Expecting an exception, none occurred");
  743. } catch (moodle_exception $e) {
  744. $this->assertInstanceOf('dml_exception', $e);
  745. }
  746. // Update records.
  747. $sql = "UPDATE {{$tablename1}}
  748. SET course = 6
  749. WHERE course = ?";
  750. $this->assertTrue($DB->execute($sql, array('3')));
  751. $this->assertEquals(2, $DB->count_records($tablename1, array('course' => 6)));
  752. // Update records with subquery condition.
  753. // Confirm that the option not using table aliases is cross-db.
  754. $sql = "UPDATE {{$tablename1}}
  755. SET course = 0
  756. WHERE NOT EXISTS (
  757. SELECT course
  758. FROM {{$tablename2}} tbl2
  759. WHERE tbl2.course = {{$tablename1}}.course
  760. AND 1 = 0)"; // Really we don't update anything, but verify the syntax is allowed.
  761. $this->assertTrue($DB->execute($sql));
  762. // Insert from one into second table.
  763. $sql = "INSERT INTO {{$tablename2}} (course)
  764. SELECT course
  765. FROM {{$tablename1}}";
  766. $this->assertTrue($DB->execute($sql));
  767. $this->assertEquals(4, $DB->count_records($tablename2));
  768. }
  769. public function test_get_recordset() {
  770. $DB = $this->tdb;
  771. $dbman = $DB->get_manager();
  772. $table = $this->get_test_table();
  773. $tablename = $table->getName();
  774. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  775. $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  776. $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
  777. $table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
  778. $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
  779. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  780. $dbman->create_table($table);
  781. $data = array(array('course' => 3, 'name' => 'record1', 'onetext'=>'abc'),
  782. array('course' => 3, 'name' => 'record2', 'onetext'=>'abcd'),
  783. array('course' => 5, 'name' => 'record3', 'onetext'=>'abcde'));
  784. foreach ($data as $key => $record) {
  785. $data[$key]['id'] = $DB->insert_record($tablename, $record);
  786. }
  787. // Standard recordset iteration.
  788. $rs = $DB->get_recordset($tablename);
  789. $this->assertInstanceOf('moodle_recordset', $rs);
  790. reset($data);
  791. foreach ($rs as $record) {
  792. $data_record = current($data);
  793. foreach ($record as $k => $v) {
  794. $this->assertEquals($data_record[$k], $v);
  795. }
  796. next($data);
  797. }
  798. $rs->close();
  799. // Iterator style usage.
  800. $rs = $DB->get_recordset($tablename);
  801. $this->assertInstanceOf('moodle_recordset', $rs);
  802. reset($data);
  803. while ($rs->valid()) {
  804. $record = $rs->current();
  805. $data_record = current($data);
  806. foreach ($record as $k => $v) {
  807. $this->assertEquals($data_record[$k], $v);
  808. }
  809. next($data);
  810. $rs->next();
  811. }
  812. $rs->close();
  813. // Make sure rewind is ignored.
  814. $rs = $DB->get_recordset($tablename);
  815. $this->assertInstanceOf('moodle_recordset', $rs);
  816. reset($data);
  817. $i = 0;
  818. foreach ($rs as $record) {
  819. $i++;
  820. $rs->rewind();
  821. if ($i > 10) {
  822. $this->fail('revind not ignored in recordsets');
  823. break;
  824. }
  825. $data_record = current($data);
  826. foreach ($record as $k => $v) {
  827. $this->assertEquals($data_record[$k], $v);
  828. }
  829. next($data);
  830. }
  831. $rs->close();
  832. // Test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int).
  833. $conditions = array('onetext' => '1');
  834. try {
  835. $rs = $DB->get_recordset($tablename, $conditions);
  836. $this->fail('An Exception is missing, expected due to equating of text fields');
  837. } catch (moodle_exception $e) {
  838. $this->assertInstanceOf('dml_exception', $e);
  839. $this->assertSame('textconditionsnotallowed', $e->errorcode);
  840. }
  841. // Test nested iteration.
  842. $rs1 = $DB->get_recordset($tablename);
  843. $i = 0;
  844. foreach ($rs1 as $record1) {
  845. $rs2 = $DB->get_recordset($tablename);
  846. $i++;
  847. $j = 0;
  848. foreach ($rs2 as $record2) {
  849. $j++;
  850. }
  851. $rs2->close();
  852. $this->assertCount($j, $data);
  853. }
  854. $rs1->close();
  855. $this->assertCount($i, $data);
  856. // Notes:
  857. // * limits are tested in test_get_recordset_sql()
  858. // * where_clause() is used internally and is tested in test_get_records()
  859. }
  860. public function test_get_recordset_static() {
  861. $DB = $this->tdb;
  862. $dbman = $DB->get_manager();
  863. $table = $this->get_test_table();
  864. $tablename = $table->getName();
  865. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  866. $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  867. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  868. $dbman->create_table($table);
  869. $DB->insert_record($tablename, array('course' => 1));
  870. $DB->insert_record($tablename, array('course' => 2));
  871. $DB->insert_record($tablename, array('course' => 3));
  872. $DB->insert_record($tablename, array('course' => 4));
  873. $rs = $DB->get_recordset($tablename, array(), 'id');
  874. $DB->set_field($tablename, 'course', 666, array('course'=>1));
  875. $DB->delete_records($tablename, array('course'=>2));
  876. $i = 0;
  877. foreach ($rs as $record) {
  878. $i++;
  879. $this->assertEquals($i, $record->course);
  880. }
  881. $rs->close();
  882. $this->assertEquals(4, $i);
  883. // Now repeat with limits because it may use different code.
  884. $DB->delete_records($tablename, array());
  885. $DB->insert_record($tablename, array('course' => 1));
  886. $DB->insert_record($tablename, array('course' => 2));
  887. $DB->insert_record($tablename, array('course' => 3));
  888. $DB->insert_record($tablename, array('course' => 4));
  889. $rs = $DB->get_recordset($tablename, array(), 'id', '*', 0, 3);
  890. $DB->set_field($tablename, 'course', 666, array('course'=>1));
  891. $DB->delete_records($tablename, array('course'=>2));
  892. $i = 0;
  893. foreach ($rs as $record) {
  894. $i++;
  895. $this->assertEquals($i, $record->course);
  896. }
  897. $rs->close();
  898. $this->assertEquals(3, $i);
  899. }
  900. public function test_get_recordset_iterator_keys() {
  901. $DB = $this->tdb;
  902. $dbman = $DB->get_manager();
  903. $table = $this->get_test_table();
  904. $tablename = $table->getName();
  905. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  906. $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
  907. $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
  908. $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
  909. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  910. $dbman->create_table($table);
  911. $data = array(array('course' => 3, 'name' => 'record1'),
  912. array('course' => 3, 'name' => 'record2'),
  913. array('course' => 5, 'name' => 'record3'));
  914. foreach ($data as $key => $record) {
  915. $data[$key]['id'] = $DB->insert_record($tablename, $record);
  916. }
  917. // Test repeated numeric keys are returned ok.
  918. $rs = $DB->get_recordset($tablename, null, null, 'course, name, id');
  919. reset($data);
  920. $count = 0;
  921. foreach ($rs as $key => $record) {
  922. $data_record = current($data);
  923. $this->assertEquals($data_record['course'], $key);
  924. next($data);
  925. $count++;
  926. }
  927. $rs->close();
  928. $this->assertEquals(3, $count);
  929. // Test string keys are returned ok.
  930. $rs = $DB->get_recordset($tablename, null, null, 'name, course, id');
  931. reset($data);
  932. $count = 0;
  933. foreach ($rs as $key => $record) {
  934. $data_record = current($data);
  935. $this->assertEquals($data_record['name'], $key);
  936. next($data);
  937. $count++;
  938. }
  939. $rs->close();
  940. $this->assertEquals(3, $count);
  941. // Test numeric not starting in 1 keys are returned ok.
  942. $rs = $DB->get_recordset($tablename, null, 'id DESC', 'id, course, name');
  943. $data = array_reverse($data);
  944. reset($data);
  945. $count = 0;
  946. foreach ($rs as $key => $record) {
  947. $data_record = current($data);
  948. $this->assertEquals($data_record['id'], $key);
  949. next($data);
  950. $count++;
  951. }
  952. $rs->close();
  953. $this->assertEquals(3, $count);
  954. }
  955. public function test_get_recordset_list() {
  956. $DB = $this->tdb;
  957. $dbman = $DB->get_manager();
  958. $table = $this->get_test_table();
  959. $tablename = $table->getName();
  960. $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  961. $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, null, null, '0');
  962. $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
  963. $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
  964. $dbman->create_table($table);
  965. $DB->insert_record($tablename, array('course' => 3));
  966. $DB->insert_record($tablename, array('course' => 3));
  967. $DB->insert_record($tablename, array('course' => 5));
  968. $DB->insert_record($tablename, array('course' => 2));
  969. $DB->insert_record($tablename, array('course' => null));
  970. $DB->insert_record($tablename, array('course' => 1));
  971. $DB->insert_record($tablename, array('course' => 0));
  972. $rs = $DB->get_recordset_list($tablename, 'co…

Large files files are truncated, but you can click here to view the full file