You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

db.php 13KB

11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. /**
  9. * Class Test_DB
  10. *
  11. * @group DB
  12. */
  13. class Test_DB extends \Test\TestCase {
  14. protected $backupGlobals = FALSE;
  15. protected static $schema_file = 'static://test_db_scheme';
  16. protected $test_prefix;
  17. /**
  18. * @var string
  19. */
  20. private $table1;
  21. /**
  22. * @var string
  23. */
  24. private $table2;
  25. /**
  26. * @var string
  27. */
  28. private $table3;
  29. /**
  30. * @var string
  31. */
  32. private $table4;
  33. /**
  34. * @var string
  35. */
  36. private $table5;
  37. protected function setUp() {
  38. parent::setUp();
  39. $dbFile = OC::$SERVERROOT.'/tests/data/db_structure.xml';
  40. $r = $this->getUniqueID('_', 4).'_';
  41. $content = file_get_contents( $dbFile );
  42. $content = str_replace( '*dbprefix*', '*dbprefix*'.$r, $content );
  43. file_put_contents( self::$schema_file, $content );
  44. OC_DB::createDbFromStructure(self::$schema_file);
  45. $this->test_prefix = $r;
  46. $this->table1 = $this->test_prefix.'cntcts_addrsbks';
  47. $this->table2 = $this->test_prefix.'cntcts_cards';
  48. $this->table3 = $this->test_prefix.'vcategory';
  49. $this->table4 = $this->test_prefix.'decimal';
  50. $this->table5 = $this->test_prefix.'uniconst';
  51. }
  52. protected function tearDown() {
  53. OC_DB::removeDBStructure(self::$schema_file);
  54. unlink(self::$schema_file);
  55. parent::tearDown();
  56. }
  57. public function testQuotes() {
  58. $query = OC_DB::prepare('SELECT `fullname` FROM `*PREFIX*'.$this->table2.'` WHERE `uri` = ?');
  59. $result = $query->execute(array('uri_1'));
  60. $this->assertTrue((bool)$result);
  61. $row = $result->fetchRow();
  62. $this->assertFalse($row);
  63. $query = OC_DB::prepare('INSERT INTO `*PREFIX*'.$this->table2.'` (`fullname`,`uri`) VALUES (?,?)');
  64. $result = $query->execute(array('fullname test', 'uri_1'));
  65. $this->assertEquals(1, $result);
  66. $query = OC_DB::prepare('SELECT `fullname`,`uri` FROM `*PREFIX*'.$this->table2.'` WHERE `uri` = ?');
  67. $result = $query->execute(array('uri_1'));
  68. $this->assertTrue((bool)$result);
  69. $row = $result->fetchRow();
  70. $this->assertArrayHasKey('fullname', $row);
  71. $this->assertEquals($row['fullname'], 'fullname test');
  72. $row = $result->fetchRow();
  73. $this->assertFalse((bool)$row); //PDO returns false, MDB2 returns null
  74. }
  75. /**
  76. * @medium
  77. */
  78. public function testNOW() {
  79. $query = OC_DB::prepare('INSERT INTO `*PREFIX*'.$this->table2.'` (`fullname`,`uri`) VALUES (NOW(),?)');
  80. $result = $query->execute(array('uri_2'));
  81. $this->assertEquals(1, $result);
  82. $query = OC_DB::prepare('SELECT `fullname`,`uri` FROM `*PREFIX*'.$this->table2.'` WHERE `uri` = ?');
  83. $result = $query->execute(array('uri_2'));
  84. $this->assertTrue((bool)$result);
  85. }
  86. public function testUNIX_TIMESTAMP() {
  87. $query = OC_DB::prepare('INSERT INTO `*PREFIX*'.$this->table2.'` (`fullname`,`uri`) VALUES (UNIX_TIMESTAMP(),?)');
  88. $result = $query->execute(array('uri_3'));
  89. $this->assertEquals(1, $result);
  90. $query = OC_DB::prepare('SELECT `fullname`,`uri` FROM `*PREFIX*'.$this->table2.'` WHERE `uri` = ?');
  91. $result = $query->execute(array('uri_3'));
  92. $this->assertTrue((bool)$result);
  93. }
  94. public function testLastInsertId() {
  95. $query = OC_DB::prepare('INSERT INTO `*PREFIX*'.$this->table2.'` (`fullname`,`uri`) VALUES (?,?)');
  96. $result1 = OC_DB::executeAudited($query, array('insertid 1','uri_1'));
  97. $id1 = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*'.$this->table2);
  98. // we don't know the id we should expect, so insert another row
  99. $result2 = OC_DB::executeAudited($query, array('insertid 2','uri_2'));
  100. $id2 = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*'.$this->table2);
  101. // now we can check if the two ids are in correct order
  102. $this->assertGreaterThan($id1, $id2);
  103. }
  104. public function testinsertIfNotExist() {
  105. $categoryEntries = array(
  106. array('user' => 'test', 'type' => 'contact', 'category' => 'Family', 'expectedResult' => 1),
  107. array('user' => 'test', 'type' => 'contact', 'category' => 'Friends', 'expectedResult' => 1),
  108. array('user' => 'test', 'type' => 'contact', 'category' => 'Coworkers', 'expectedResult' => 1),
  109. array('user' => 'test', 'type' => 'contact', 'category' => 'Coworkers', 'expectedResult' => 0),
  110. array('user' => 'test', 'type' => 'contact', 'category' => 'School', 'expectedResult' => 1),
  111. );
  112. foreach($categoryEntries as $entry) {
  113. $result = \OCP\DB::insertIfNotExist('*PREFIX*'.$this->table3,
  114. array(
  115. 'uid' => $entry['user'],
  116. 'type' => $entry['type'],
  117. 'category' => $entry['category'],
  118. ));
  119. $this->assertEquals($entry['expectedResult'], $result);
  120. }
  121. $query = OC_DB::prepare('SELECT * FROM `*PREFIX*'.$this->table3.'`');
  122. $result = $query->execute();
  123. $this->assertTrue((bool)$result);
  124. $this->assertEquals(4, count($result->fetchAll()));
  125. }
  126. public function testInsertIfNotExistNull() {
  127. $categoryEntries = array(
  128. array('addressbookid' => 123, 'fullname' => null, 'expectedResult' => 1),
  129. array('addressbookid' => 123, 'fullname' => null, 'expectedResult' => 0),
  130. array('addressbookid' => 123, 'fullname' => 'test', 'expectedResult' => 1),
  131. );
  132. foreach($categoryEntries as $entry) {
  133. $result = \OCP\DB::insertIfNotExist('*PREFIX*'.$this->table2,
  134. array(
  135. 'addressbookid' => $entry['addressbookid'],
  136. 'fullname' => $entry['fullname'],
  137. ));
  138. $this->assertEquals($entry['expectedResult'], $result);
  139. }
  140. $query = OC_DB::prepare('SELECT * FROM `*PREFIX*'.$this->table2.'`');
  141. $result = $query->execute();
  142. $this->assertTrue((bool)$result);
  143. $this->assertEquals(2, count($result->fetchAll()));
  144. }
  145. public function testInsertIfNotExistDonTOverwrite() {
  146. $fullName = 'fullname test';
  147. $uri = 'uri_1';
  148. $carddata = 'This is a vCard';
  149. // Normal test to have same known data inserted.
  150. $query = OC_DB::prepare('INSERT INTO `*PREFIX*'.$this->table2.'` (`fullname`, `uri`, `carddata`) VALUES (?, ?, ?)');
  151. $result = $query->execute(array($fullName, $uri, $carddata));
  152. $this->assertEquals(1, $result);
  153. $query = OC_DB::prepare('SELECT `fullname`, `uri`, `carddata` FROM `*PREFIX*'.$this->table2.'` WHERE `uri` = ?');
  154. $result = $query->execute(array($uri));
  155. $this->assertTrue((bool)$result);
  156. $rowset = $result->fetchAll();
  157. $this->assertEquals(1, count($rowset));
  158. $this->assertArrayHasKey('carddata', $rowset[0]);
  159. $this->assertEquals($carddata, $rowset[0]['carddata']);
  160. // Try to insert a new row
  161. $result = \OCP\DB::insertIfNotExist('*PREFIX*'.$this->table2,
  162. array(
  163. 'fullname' => $fullName,
  164. 'uri' => $uri,
  165. ));
  166. $this->assertEquals(0, $result);
  167. $query = OC_DB::prepare('SELECT `fullname`, `uri`, `carddata` FROM `*PREFIX*'.$this->table2.'` WHERE `uri` = ?');
  168. $result = $query->execute(array($uri));
  169. $this->assertTrue((bool)$result);
  170. // Test that previously inserted data isn't overwritten
  171. // And that a new row hasn't been inserted.
  172. $rowset = $result->fetchAll();
  173. $this->assertEquals(1, count($rowset));
  174. $this->assertArrayHasKey('carddata', $rowset[0]);
  175. $this->assertEquals($carddata, $rowset[0]['carddata']);
  176. }
  177. public function testInsertIfNotExistsViolating() {
  178. $result = \OCP\DB::insertIfNotExist('*PREFIX*'.$this->table5,
  179. array(
  180. 'storage' => 1,
  181. 'path_hash' => md5('welcome.txt'),
  182. 'etag' => $this->getUniqueID()
  183. ));
  184. $this->assertEquals(1, $result);
  185. $result = \OCP\DB::insertIfNotExist('*PREFIX*'.$this->table5,
  186. array(
  187. 'storage' => 1,
  188. 'path_hash' => md5('welcome.txt'),
  189. 'etag' => $this->getUniqueID()
  190. ),['storage', 'path_hash']);
  191. $this->assertEquals(0, $result);
  192. }
  193. public function insertIfNotExistsViolatingThrows() {
  194. return [
  195. [null],
  196. [['etag']],
  197. ];
  198. }
  199. /**
  200. * @dataProvider insertIfNotExistsViolatingThrows
  201. * @expectedException \Doctrine\DBAL\Exception\UniqueConstraintViolationException
  202. *
  203. * @param array $compareKeys
  204. */
  205. public function testInsertIfNotExistsViolatingThrows($compareKeys) {
  206. $result = \OCP\DB::insertIfNotExist('*PREFIX*'.$this->table5,
  207. array(
  208. 'storage' => 1,
  209. 'path_hash' => md5('welcome.txt'),
  210. 'etag' => $this->getUniqueID()
  211. ));
  212. $this->assertEquals(1, $result);
  213. $result = \OCP\DB::insertIfNotExist('*PREFIX*'.$this->table5,
  214. array(
  215. 'storage' => 1,
  216. 'path_hash' => md5('welcome.txt'),
  217. 'etag' => $this->getUniqueID()
  218. ), $compareKeys);
  219. $this->assertEquals(0, $result);
  220. }
  221. public function testUtf8Data() {
  222. $table = "*PREFIX*{$this->table2}";
  223. $expected = "Ћö雙喜\xE2\x80\xA2";
  224. $query = OC_DB::prepare("INSERT INTO `$table` (`fullname`, `uri`, `carddata`) VALUES (?, ?, ?)");
  225. $result = $query->execute(array($expected, 'uri_1', 'This is a vCard'));
  226. $this->assertEquals(1, $result);
  227. $actual = OC_DB::prepare("SELECT `fullname` FROM `$table`")->execute()->fetchOne();
  228. $this->assertSame($expected, $actual);
  229. }
  230. /**
  231. * Insert, select and delete decimal(12,2) values
  232. * @dataProvider decimalData
  233. */
  234. public function testDecimal($insert, $expect) {
  235. $table = "*PREFIX*" . $this->table4;
  236. $rowname = 'decimaltest';
  237. $query = OC_DB::prepare('INSERT INTO `' . $table . '` (`' . $rowname . '`) VALUES (?)');
  238. $result = $query->execute(array($insert));
  239. $this->assertEquals(1, $result);
  240. $query = OC_DB::prepare('SELECT `' . $rowname . '` FROM `' . $table . '`');
  241. $result = $query->execute();
  242. $this->assertTrue((bool)$result);
  243. $row = $result->fetchRow();
  244. $this->assertArrayHasKey($rowname, $row);
  245. $this->assertEquals($expect, $row[$rowname]);
  246. $query = OC_DB::prepare('DELETE FROM `' . $table . '`');
  247. $result = $query->execute();
  248. $this->assertTrue((bool)$result);
  249. }
  250. public function decimalData() {
  251. return [
  252. ['1337133713.37', '1337133713.37'],
  253. ['1234567890', '1234567890.00'],
  254. ];
  255. }
  256. public function testUpdateAffectedRowsNoMatch() {
  257. $this->insertCardData('fullname1', 'uri1');
  258. // The WHERE clause does not match any rows
  259. $this->assertSame(0, $this->updateCardData('fullname3', 'uri2'));
  260. }
  261. public function testUpdateAffectedRowsDifferent() {
  262. $this->insertCardData('fullname1', 'uri1');
  263. // The WHERE clause matches a single row and the value we are updating
  264. // is different from the one already present.
  265. $this->assertSame(1, $this->updateCardData('fullname1', 'uri2'));
  266. }
  267. public function testUpdateAffectedRowsSame() {
  268. $this->insertCardData('fullname1', 'uri1');
  269. // The WHERE clause matches a single row and the value we are updating
  270. // to is the same as the one already present. MySQL reports 0 here when
  271. // the PDO::MYSQL_ATTR_FOUND_ROWS flag is not specified.
  272. $this->assertSame(1, $this->updateCardData('fullname1', 'uri1'));
  273. }
  274. public function testUpdateAffectedRowsMultiple() {
  275. $this->insertCardData('fullname1', 'uri1');
  276. $this->insertCardData('fullname2', 'uri2');
  277. // The WHERE clause matches two rows. One row contains a value that
  278. // needs to be updated, the other one already contains the value we are
  279. // updating to. MySQL reports 1 here when the PDO::MYSQL_ATTR_FOUND_ROWS
  280. // flag is not specified.
  281. $query = OC_DB::prepare("UPDATE `*PREFIX*{$this->table2}` SET `uri` = ?");
  282. $this->assertSame(2, $query->execute(array('uri1')));
  283. }
  284. protected function insertCardData($fullname, $uri) {
  285. $query = OC_DB::prepare("INSERT INTO `*PREFIX*{$this->table2}` (`fullname`, `uri`, `carddata`) VALUES (?, ?, ?)");
  286. $this->assertSame(1, $query->execute(array($fullname, $uri, $this->getUniqueID())));
  287. }
  288. protected function updateCardData($fullname, $uri) {
  289. $query = OC_DB::prepare("UPDATE `*PREFIX*{$this->table2}` SET `uri` = ? WHERE `fullname` = ?");
  290. return $query->execute(array($uri, $fullname));
  291. }
  292. public function testILIKE() {
  293. $table = "*PREFIX*{$this->table2}";
  294. $query = OC_DB::prepare("INSERT INTO `$table` (`fullname`, `uri`, `carddata`) VALUES (?, ?, ?)");
  295. $query->execute(array('fooBAR', 'foo', 'bar'));
  296. $query = OC_DB::prepare("SELECT * FROM `$table` WHERE `fullname` LIKE ?");
  297. $result = $query->execute(array('foobar'));
  298. $this->assertCount(0, $result->fetchAll());
  299. $query = OC_DB::prepare("SELECT * FROM `$table` WHERE `fullname` ILIKE ?");
  300. $result = $query->execute(array('foobar'));
  301. $this->assertCount(1, $result->fetchAll());
  302. $query = OC_DB::prepare("SELECT * FROM `$table` WHERE `fullname` ILIKE ?");
  303. $result = $query->execute(array('foo'));
  304. $this->assertCount(0, $result->fetchAll());
  305. }
  306. public function testILIKEWildcard() {
  307. $table = "*PREFIX*{$this->table2}";
  308. $query = OC_DB::prepare("INSERT INTO `$table` (`fullname`, `uri`, `carddata`) VALUES (?, ?, ?)");
  309. $query->execute(array('FooBAR', 'foo', 'bar'));
  310. $query = OC_DB::prepare("SELECT * FROM `$table` WHERE `fullname` LIKE ?");
  311. $result = $query->execute(array('%bar'));
  312. $this->assertCount(0, $result->fetchAll());
  313. $query = OC_DB::prepare("SELECT * FROM `$table` WHERE `fullname` LIKE ?");
  314. $result = $query->execute(array('foo%'));
  315. $this->assertCount(0, $result->fetchAll());
  316. $query = OC_DB::prepare("SELECT * FROM `$table` WHERE `fullname` LIKE ?");
  317. $result = $query->execute(array('%ba%'));
  318. $this->assertCount(0, $result->fetchAll());
  319. $query = OC_DB::prepare("SELECT * FROM `$table` WHERE `fullname` ILIKE ?");
  320. $result = $query->execute(array('%bar'));
  321. $this->assertCount(1, $result->fetchAll());
  322. $query = OC_DB::prepare("SELECT * FROM `$table` WHERE `fullname` ILIKE ?");
  323. $result = $query->execute(array('foo%'));
  324. $this->assertCount(1, $result->fetchAll());
  325. $query = OC_DB::prepare("SELECT * FROM `$table` WHERE `fullname` ILIKE ?");
  326. $result = $query->execute(array('%ba%'));
  327. $this->assertCount(1, $result->fetchAll());
  328. }
  329. }