1
0

QueryBuilderTest.php 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace Test\DB\QueryBuilder;
  8. use Doctrine\DBAL\Query\Expression\CompositeExpression;
  9. use Doctrine\DBAL\Query\QueryException;
  10. use OC\DB\QueryBuilder\Literal;
  11. use OC\DB\QueryBuilder\Parameter;
  12. use OC\DB\QueryBuilder\QueryBuilder;
  13. use OC\SystemConfig;
  14. use OCP\DB\IResult;
  15. use OCP\DB\QueryBuilder\IQueryBuilder;
  16. use OCP\DB\QueryBuilder\IQueryFunction;
  17. use OCP\IDBConnection;
  18. use Psr\Log\LoggerInterface;
  19. /**
  20. * Class QueryBuilderTest
  21. *
  22. * @group DB
  23. *
  24. * @package Test\DB\QueryBuilder
  25. */
  26. class QueryBuilderTest extends \Test\TestCase {
  27. /** @var QueryBuilder */
  28. protected $queryBuilder;
  29. /** @var IDBConnection */
  30. protected $connection;
  31. /** @var SystemConfig|\PHPUnit\Framework\MockObject\MockObject */
  32. protected $config;
  33. /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
  34. protected $logger;
  35. protected function setUp(): void {
  36. parent::setUp();
  37. $this->connection = \OC::$server->getDatabaseConnection();
  38. $this->config = $this->createMock(SystemConfig::class);
  39. $this->logger = $this->createMock(LoggerInterface::class);
  40. $this->queryBuilder = new QueryBuilder($this->connection, $this->config, $this->logger);
  41. }
  42. protected function createTestingRows($appId = 'testFirstResult') {
  43. $qB = $this->connection->getQueryBuilder();
  44. for ($i = 1; $i < 10; $i++) {
  45. $qB->insert('*PREFIX*appconfig')
  46. ->values([
  47. 'appid' => $qB->expr()->literal($appId),
  48. 'configkey' => $qB->expr()->literal('testing' . $i),
  49. 'configvalue' => $qB->expr()->literal(100 - $i),
  50. ])
  51. ->execute();
  52. }
  53. }
  54. protected function getTestingRows(QueryBuilder $queryBuilder) {
  55. $queryBuilder->select('configvalue')
  56. ->from('*PREFIX*appconfig')
  57. ->where($queryBuilder->expr()->eq(
  58. 'appid',
  59. $queryBuilder->expr()->literal('testFirstResult')
  60. ))
  61. ->orderBy('configkey', 'ASC');
  62. $query = $queryBuilder->execute();
  63. $rows = [];
  64. while ($row = $query->fetch()) {
  65. $rows[] = $row['configvalue'];
  66. }
  67. $query->closeCursor();
  68. return $rows;
  69. }
  70. protected function deleteTestingRows($appId = 'testFirstResult') {
  71. $qB = $this->connection->getQueryBuilder();
  72. $qB->delete('*PREFIX*appconfig')
  73. ->where($qB->expr()->eq('appid', $qB->expr()->literal($appId)))
  74. ->execute();
  75. }
  76. public function dataFirstResult() {
  77. return [
  78. [0, [99, 98, 97, 96, 95, 94, 93, 92, 91]],
  79. [0, [99, 98, 97, 96, 95, 94, 93, 92, 91]],
  80. [1, [98, 97, 96, 95, 94, 93, 92, 91]],
  81. [5, [94, 93, 92, 91]],
  82. ];
  83. }
  84. /**
  85. * @dataProvider dataFirstResult
  86. *
  87. * @param int|null $firstResult
  88. * @param array $expectedSet
  89. */
  90. public function testFirstResult($firstResult, $expectedSet): void {
  91. $this->deleteTestingRows();
  92. $this->createTestingRows();
  93. if ($firstResult !== null) {
  94. $this->queryBuilder->setFirstResult($firstResult);
  95. }
  96. $this->assertSame(
  97. $firstResult ?? 0,
  98. $this->queryBuilder->getFirstResult()
  99. );
  100. $rows = $this->getTestingRows($this->queryBuilder);
  101. $this->assertCount(sizeof($expectedSet), $rows);
  102. $this->assertEquals($expectedSet, $rows);
  103. $this->deleteTestingRows();
  104. }
  105. public function dataMaxResults() {
  106. return [
  107. [null, [99, 98, 97, 96, 95, 94, 93, 92, 91]],
  108. // Limit 0 gives mixed results: either all entries or none is returned
  109. //[0, []],
  110. [1, [99]],
  111. [5, [99, 98, 97, 96, 95]],
  112. ];
  113. }
  114. /**
  115. * @dataProvider dataMaxResults
  116. *
  117. * @param int $maxResult
  118. * @param array $expectedSet
  119. */
  120. public function testMaxResults($maxResult, $expectedSet): void {
  121. $this->deleteTestingRows();
  122. $this->createTestingRows();
  123. if ($maxResult !== null) {
  124. $this->queryBuilder->setMaxResults($maxResult);
  125. }
  126. $this->assertSame(
  127. $maxResult,
  128. $this->queryBuilder->getMaxResults()
  129. );
  130. $rows = $this->getTestingRows($this->queryBuilder);
  131. $this->assertCount(sizeof($expectedSet), $rows);
  132. $this->assertEquals($expectedSet, $rows);
  133. $this->deleteTestingRows();
  134. }
  135. public function dataSelect() {
  136. $config = $this->createMock(SystemConfig::class);
  137. $logger = $this->createMock(LoggerInterface::class);
  138. $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
  139. return [
  140. // select('column1')
  141. [['configvalue'], ['configvalue' => '99']],
  142. // select('column1', 'column2')
  143. [['configvalue', 'configkey'], ['configvalue' => '99', 'configkey' => 'testing1']],
  144. // select(['column1', 'column2'])
  145. [[['configvalue', 'configkey']], ['configvalue' => '99', 'configkey' => 'testing1']],
  146. // select(new Literal('column1'))
  147. [[$queryBuilder->expr()->literal('column1')], [], 'column1'],
  148. // select('column1', 'column2')
  149. [[$queryBuilder->expr()->literal('column1'), 'configkey'], ['configkey' => 'testing1'], 'column1'],
  150. // select(['column1', 'column2'])
  151. [[[$queryBuilder->expr()->literal('column1'), 'configkey']], ['configkey' => 'testing1'], 'column1'],
  152. ];
  153. }
  154. /**
  155. * @dataProvider dataSelect
  156. *
  157. * @param array $selectArguments
  158. * @param array $expected
  159. * @param string $expectedLiteral
  160. */
  161. public function testSelect($selectArguments, $expected, $expectedLiteral = ''): void {
  162. $this->deleteTestingRows();
  163. $this->createTestingRows();
  164. call_user_func_array(
  165. [$this->queryBuilder, 'select'],
  166. $selectArguments
  167. );
  168. $this->queryBuilder->from('*PREFIX*appconfig')
  169. ->where($this->queryBuilder->expr()->eq(
  170. 'appid',
  171. $this->queryBuilder->expr()->literal('testFirstResult')
  172. ))
  173. ->orderBy('configkey', 'ASC')
  174. ->setMaxResults(1);
  175. $query = $this->queryBuilder->execute();
  176. $row = $query->fetch();
  177. $query->closeCursor();
  178. foreach ($expected as $key => $value) {
  179. $this->assertArrayHasKey($key, $row);
  180. $this->assertEquals($value, $row[$key]);
  181. unset($row[$key]);
  182. }
  183. if ($expectedLiteral) {
  184. $this->assertEquals([$expectedLiteral], array_values($row));
  185. } else {
  186. $this->assertEmpty($row);
  187. }
  188. $this->deleteTestingRows();
  189. }
  190. public function dataSelectAlias() {
  191. $config = $this->createMock(SystemConfig::class);
  192. $logger = $this->createMock(LoggerInterface::class);
  193. $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
  194. return [
  195. ['configvalue', 'cv', ['cv' => '99']],
  196. [$queryBuilder->expr()->literal('column1'), 'thing', ['thing' => 'column1']],
  197. ];
  198. }
  199. /**
  200. * @dataProvider dataSelectAlias
  201. *
  202. * @param mixed $select
  203. * @param array $alias
  204. * @param array $expected
  205. */
  206. public function testSelectAlias($select, $alias, $expected): void {
  207. $this->deleteTestingRows();
  208. $this->createTestingRows();
  209. $this->queryBuilder->selectAlias($select, $alias);
  210. $this->queryBuilder->from('*PREFIX*appconfig')
  211. ->where($this->queryBuilder->expr()->eq(
  212. 'appid',
  213. $this->queryBuilder->expr()->literal('testFirstResult')
  214. ))
  215. ->orderBy('configkey', 'ASC')
  216. ->setMaxResults(1);
  217. $query = $this->queryBuilder->execute();
  218. $row = $query->fetch();
  219. $query->closeCursor();
  220. $this->assertEquals(
  221. $expected,
  222. $row
  223. );
  224. $this->deleteTestingRows();
  225. }
  226. public function testSelectDistinct(): void {
  227. $this->deleteTestingRows('testFirstResult1');
  228. $this->deleteTestingRows('testFirstResult2');
  229. $this->createTestingRows('testFirstResult1');
  230. $this->createTestingRows('testFirstResult2');
  231. $this->queryBuilder->selectDistinct('appid');
  232. $this->queryBuilder->from('*PREFIX*appconfig')
  233. ->where($this->queryBuilder->expr()->in(
  234. 'appid',
  235. [$this->queryBuilder->expr()->literal('testFirstResult1'), $this->queryBuilder->expr()->literal('testFirstResult2')]
  236. ))
  237. ->orderBy('appid', 'DESC');
  238. $query = $this->queryBuilder->execute();
  239. $rows = $query->fetchAll();
  240. $query->closeCursor();
  241. $this->assertEquals(
  242. [['appid' => 'testFirstResult2'], ['appid' => 'testFirstResult1']],
  243. $rows
  244. );
  245. $this->deleteTestingRows('testFirstResult1');
  246. $this->deleteTestingRows('testFirstResult2');
  247. }
  248. public function testSelectDistinctMultiple(): void {
  249. $this->deleteTestingRows('testFirstResult1');
  250. $this->deleteTestingRows('testFirstResult2');
  251. $this->createTestingRows('testFirstResult1');
  252. $this->createTestingRows('testFirstResult2');
  253. $this->queryBuilder->selectDistinct(['appid', 'configkey']);
  254. $this->queryBuilder->from('*PREFIX*appconfig')
  255. ->where($this->queryBuilder->expr()->eq(
  256. 'appid',
  257. $this->queryBuilder->expr()->literal('testFirstResult1')
  258. ))
  259. ->orderBy('configkey', 'ASC');
  260. $query = $this->queryBuilder->execute();
  261. $rows = $query->fetchAll();
  262. $query->closeCursor();
  263. $this->assertEquals(
  264. [
  265. ['appid' => 'testFirstResult1', 'configkey' => 'testing1'],
  266. ['appid' => 'testFirstResult1', 'configkey' => 'testing2'],
  267. ['appid' => 'testFirstResult1', 'configkey' => 'testing3'],
  268. ['appid' => 'testFirstResult1', 'configkey' => 'testing4'],
  269. ['appid' => 'testFirstResult1', 'configkey' => 'testing5'],
  270. ['appid' => 'testFirstResult1', 'configkey' => 'testing6'],
  271. ['appid' => 'testFirstResult1', 'configkey' => 'testing7'],
  272. ['appid' => 'testFirstResult1', 'configkey' => 'testing8'],
  273. ['appid' => 'testFirstResult1', 'configkey' => 'testing9'],
  274. ],
  275. $rows
  276. );
  277. $this->deleteTestingRows('testFirstResult1');
  278. $this->deleteTestingRows('testFirstResult2');
  279. }
  280. public function dataAddSelect() {
  281. $config = $this->createMock(SystemConfig::class);
  282. $logger = $this->createMock(LoggerInterface::class);
  283. $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
  284. return [
  285. // addSelect('column1')
  286. [['configvalue'], ['appid' => 'testFirstResult', 'configvalue' => '99']],
  287. // addSelect('column1', 'column2')
  288. [['configvalue', 'configkey'], ['appid' => 'testFirstResult', 'configvalue' => '99', 'configkey' => 'testing1']],
  289. // addSelect(['column1', 'column2'])
  290. [[['configvalue', 'configkey']], ['appid' => 'testFirstResult', 'configvalue' => '99', 'configkey' => 'testing1']],
  291. // select(new Literal('column1'))
  292. [[$queryBuilder->expr()->literal('column1')], ['appid' => 'testFirstResult'], 'column1'],
  293. // select('column1', 'column2')
  294. [[$queryBuilder->expr()->literal('column1'), 'configkey'], ['appid' => 'testFirstResult', 'configkey' => 'testing1'], 'column1'],
  295. // select(['column1', 'column2'])
  296. [[[$queryBuilder->expr()->literal('column1'), 'configkey']], ['appid' => 'testFirstResult', 'configkey' => 'testing1'], 'column1'],
  297. ];
  298. }
  299. /**
  300. * @dataProvider dataAddSelect
  301. *
  302. * @param array $selectArguments
  303. * @param array $expected
  304. * @param string $expectedLiteral
  305. */
  306. public function testAddSelect($selectArguments, $expected, $expectedLiteral = ''): void {
  307. $this->deleteTestingRows();
  308. $this->createTestingRows();
  309. $this->queryBuilder->select('appid');
  310. call_user_func_array(
  311. [$this->queryBuilder, 'addSelect'],
  312. $selectArguments
  313. );
  314. $this->queryBuilder->from('*PREFIX*appconfig')
  315. ->where($this->queryBuilder->expr()->eq(
  316. 'appid',
  317. $this->queryBuilder->expr()->literal('testFirstResult')
  318. ))
  319. ->orderBy('configkey', 'ASC')
  320. ->setMaxResults(1);
  321. $query = $this->queryBuilder->execute();
  322. $row = $query->fetch();
  323. $query->closeCursor();
  324. foreach ($expected as $key => $value) {
  325. $this->assertArrayHasKey($key, $row);
  326. $this->assertEquals($value, $row[$key]);
  327. unset($row[$key]);
  328. }
  329. if ($expectedLiteral) {
  330. $this->assertEquals([$expectedLiteral], array_values($row));
  331. } else {
  332. $this->assertEmpty($row);
  333. }
  334. $this->deleteTestingRows();
  335. }
  336. public function dataDelete() {
  337. return [
  338. ['data', null, ['table' => '`*PREFIX*data`', 'alias' => null], '`*PREFIX*data`'],
  339. ['data', 't', ['table' => '`*PREFIX*data`', 'alias' => 't'], '`*PREFIX*data` t'],
  340. ];
  341. }
  342. /**
  343. * @dataProvider dataDelete
  344. *
  345. * @param string $tableName
  346. * @param string $tableAlias
  347. * @param array $expectedQueryPart
  348. * @param string $expectedQuery
  349. */
  350. public function testDelete($tableName, $tableAlias, $expectedQueryPart, $expectedQuery): void {
  351. $this->queryBuilder->delete($tableName, $tableAlias);
  352. $this->assertSame(
  353. $expectedQueryPart,
  354. $this->queryBuilder->getQueryPart('from')
  355. );
  356. $this->assertSame(
  357. 'DELETE FROM ' . $expectedQuery,
  358. $this->queryBuilder->getSQL()
  359. );
  360. }
  361. public function dataUpdate() {
  362. return [
  363. ['data', null, ['table' => '`*PREFIX*data`', 'alias' => null], '`*PREFIX*data`'],
  364. ['data', 't', ['table' => '`*PREFIX*data`', 'alias' => 't'], '`*PREFIX*data` t'],
  365. ];
  366. }
  367. /**
  368. * @dataProvider dataUpdate
  369. *
  370. * @param string $tableName
  371. * @param string $tableAlias
  372. * @param array $expectedQueryPart
  373. * @param string $expectedQuery
  374. */
  375. public function testUpdate($tableName, $tableAlias, $expectedQueryPart, $expectedQuery): void {
  376. $this->queryBuilder->update($tableName, $tableAlias);
  377. $this->assertSame(
  378. $expectedQueryPart,
  379. $this->queryBuilder->getQueryPart('from')
  380. );
  381. $this->assertSame(
  382. 'UPDATE ' . $expectedQuery . ' SET ',
  383. $this->queryBuilder->getSQL()
  384. );
  385. }
  386. public function dataInsert() {
  387. return [
  388. ['data', ['table' => '`*PREFIX*data`'], '`*PREFIX*data`'],
  389. ];
  390. }
  391. /**
  392. * @dataProvider dataInsert
  393. *
  394. * @param string $tableName
  395. * @param array $expectedQueryPart
  396. * @param string $expectedQuery
  397. */
  398. public function testInsert($tableName, $expectedQueryPart, $expectedQuery): void {
  399. $this->queryBuilder->insert($tableName);
  400. $this->assertSame(
  401. $expectedQueryPart,
  402. $this->queryBuilder->getQueryPart('from')
  403. );
  404. $this->assertSame(
  405. 'INSERT INTO ' . $expectedQuery . ' () VALUES()',
  406. $this->queryBuilder->getSQL()
  407. );
  408. }
  409. public function dataFrom() {
  410. $config = $this->createMock(SystemConfig::class);
  411. $logger = $this->createMock(LoggerInterface::class);
  412. $qb = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
  413. return [
  414. [$qb->createFunction('(' . $qb->select('*')->from('test')->getSQL() . ')'), 'q', null, null, [
  415. ['table' => '(SELECT * FROM `*PREFIX*test`)', 'alias' => '`q`']
  416. ], '(SELECT * FROM `*PREFIX*test`) `q`'],
  417. ['data', null, null, null, [['table' => '`*PREFIX*data`', 'alias' => null]], '`*PREFIX*data`'],
  418. ['data', 't', null, null, [['table' => '`*PREFIX*data`', 'alias' => '`t`']], '`*PREFIX*data` `t`'],
  419. ['data1', null, 'data2', null, [
  420. ['table' => '`*PREFIX*data1`', 'alias' => null],
  421. ['table' => '`*PREFIX*data2`', 'alias' => null]
  422. ], '`*PREFIX*data1`, `*PREFIX*data2`'],
  423. ['data', 't1', 'data', 't2', [
  424. ['table' => '`*PREFIX*data`', 'alias' => '`t1`'],
  425. ['table' => '`*PREFIX*data`', 'alias' => '`t2`']
  426. ], '`*PREFIX*data` `t1`, `*PREFIX*data` `t2`'],
  427. ];
  428. }
  429. /**
  430. * @dataProvider dataFrom
  431. *
  432. * @param string|IQueryFunction $table1Name
  433. * @param string $table1Alias
  434. * @param string|IQueryFunction $table2Name
  435. * @param string $table2Alias
  436. * @param array $expectedQueryPart
  437. * @param string $expectedQuery
  438. */
  439. public function testFrom($table1Name, $table1Alias, $table2Name, $table2Alias, $expectedQueryPart, $expectedQuery): void {
  440. $this->queryBuilder->from($table1Name, $table1Alias);
  441. if ($table2Name !== null) {
  442. $this->queryBuilder->from($table2Name, $table2Alias);
  443. }
  444. $this->assertSame(
  445. $expectedQueryPart,
  446. $this->queryBuilder->getQueryPart('from')
  447. );
  448. $this->assertSame(
  449. 'SELECT FROM ' . $expectedQuery,
  450. $this->queryBuilder->getSQL()
  451. );
  452. }
  453. public function dataJoin() {
  454. return [
  455. [
  456. 'd1', 'data2', null, null,
  457. ['`d1`' => [['joinType' => 'inner', 'joinTable' => '`*PREFIX*data2`', 'joinAlias' => null, 'joinCondition' => null]]],
  458. '`*PREFIX*data1` `d1` INNER JOIN `*PREFIX*data2` '
  459. ],
  460. [
  461. 'd1', 'data2', 'd2', null,
  462. ['`d1`' => [['joinType' => 'inner', 'joinTable' => '`*PREFIX*data2`', 'joinAlias' => '`d2`', 'joinCondition' => null]]],
  463. '`*PREFIX*data1` `d1` INNER JOIN `*PREFIX*data2` `d2`'
  464. ],
  465. [
  466. 'd1', 'data2', 'd2', '`d1`.`field1` = `d2`.`field2`',
  467. ['`d1`' => [['joinType' => 'inner', 'joinTable' => '`*PREFIX*data2`', 'joinAlias' => '`d2`', 'joinCondition' => '`d1`.`field1` = `d2`.`field2`']]],
  468. '`*PREFIX*data1` `d1` INNER JOIN `*PREFIX*data2` `d2` ON `d1`.`field1` = `d2`.`field2`'
  469. ],
  470. ];
  471. }
  472. /**
  473. * @dataProvider dataJoin
  474. *
  475. * @param string $fromAlias
  476. * @param string $tableName
  477. * @param string $tableAlias
  478. * @param string $condition
  479. * @param array $expectedQueryPart
  480. * @param string $expectedQuery
  481. */
  482. public function testJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void {
  483. $this->queryBuilder->from('data1', 'd1');
  484. $this->queryBuilder->join(
  485. $fromAlias,
  486. $tableName,
  487. $tableAlias,
  488. $condition
  489. );
  490. $this->assertSame(
  491. $expectedQueryPart,
  492. $this->queryBuilder->getQueryPart('join')
  493. );
  494. $this->assertSame(
  495. 'SELECT FROM ' . $expectedQuery,
  496. $this->queryBuilder->getSQL()
  497. );
  498. }
  499. /**
  500. * @dataProvider dataJoin
  501. *
  502. * @param string $fromAlias
  503. * @param string $tableName
  504. * @param string $tableAlias
  505. * @param string $condition
  506. * @param array $expectedQueryPart
  507. * @param string $expectedQuery
  508. */
  509. public function testInnerJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void {
  510. $this->queryBuilder->from('data1', 'd1');
  511. $this->queryBuilder->innerJoin(
  512. $fromAlias,
  513. $tableName,
  514. $tableAlias,
  515. $condition
  516. );
  517. $this->assertSame(
  518. $expectedQueryPart,
  519. $this->queryBuilder->getQueryPart('join')
  520. );
  521. $this->assertSame(
  522. 'SELECT FROM ' . $expectedQuery,
  523. $this->queryBuilder->getSQL()
  524. );
  525. }
  526. public function dataLeftJoin() {
  527. return [
  528. [
  529. 'd1', 'data2', null, null,
  530. ['`d1`' => [['joinType' => 'left', 'joinTable' => '`*PREFIX*data2`', 'joinAlias' => null, 'joinCondition' => null]]],
  531. '`*PREFIX*data1` `d1` LEFT JOIN `*PREFIX*data2` '
  532. ],
  533. [
  534. 'd1', 'data2', 'd2', null,
  535. ['`d1`' => [['joinType' => 'left', 'joinTable' => '`*PREFIX*data2`', 'joinAlias' => '`d2`', 'joinCondition' => null]]],
  536. '`*PREFIX*data1` `d1` LEFT JOIN `*PREFIX*data2` `d2`'
  537. ],
  538. [
  539. 'd1', 'data2', 'd2', '`d1`.`field1` = `d2`.`field2`',
  540. ['`d1`' => [['joinType' => 'left', 'joinTable' => '`*PREFIX*data2`', 'joinAlias' => '`d2`', 'joinCondition' => '`d1`.`field1` = `d2`.`field2`']]],
  541. '`*PREFIX*data1` `d1` LEFT JOIN `*PREFIX*data2` `d2` ON `d1`.`field1` = `d2`.`field2`'
  542. ],
  543. ];
  544. }
  545. /**
  546. * @dataProvider dataLeftJoin
  547. *
  548. * @param string $fromAlias
  549. * @param string $tableName
  550. * @param string $tableAlias
  551. * @param string $condition
  552. * @param array $expectedQueryPart
  553. * @param string $expectedQuery
  554. */
  555. public function testLeftJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void {
  556. $this->queryBuilder->from('data1', 'd1');
  557. $this->queryBuilder->leftJoin(
  558. $fromAlias,
  559. $tableName,
  560. $tableAlias,
  561. $condition
  562. );
  563. $this->assertSame(
  564. $expectedQueryPart,
  565. $this->queryBuilder->getQueryPart('join')
  566. );
  567. $this->assertSame(
  568. 'SELECT FROM ' . $expectedQuery,
  569. $this->queryBuilder->getSQL()
  570. );
  571. }
  572. public function dataRightJoin() {
  573. return [
  574. [
  575. 'd1', 'data2', null, null,
  576. ['`d1`' => [['joinType' => 'right', 'joinTable' => '`*PREFIX*data2`', 'joinAlias' => null, 'joinCondition' => null]]],
  577. '`*PREFIX*data1` `d1` RIGHT JOIN `*PREFIX*data2` '
  578. ],
  579. [
  580. 'd1', 'data2', 'd2', null,
  581. ['`d1`' => [['joinType' => 'right', 'joinTable' => '`*PREFIX*data2`', 'joinAlias' => '`d2`', 'joinCondition' => null]]],
  582. '`*PREFIX*data1` `d1` RIGHT JOIN `*PREFIX*data2` `d2`'
  583. ],
  584. [
  585. 'd1', 'data2', 'd2', '`d1`.`field1` = `d2`.`field2`',
  586. ['`d1`' => [['joinType' => 'right', 'joinTable' => '`*PREFIX*data2`', 'joinAlias' => '`d2`', 'joinCondition' => '`d1`.`field1` = `d2`.`field2`']]],
  587. '`*PREFIX*data1` `d1` RIGHT JOIN `*PREFIX*data2` `d2` ON `d1`.`field1` = `d2`.`field2`'
  588. ],
  589. ];
  590. }
  591. /**
  592. * @dataProvider dataRightJoin
  593. *
  594. * @param string $fromAlias
  595. * @param string $tableName
  596. * @param string $tableAlias
  597. * @param string $condition
  598. * @param array $expectedQueryPart
  599. * @param string $expectedQuery
  600. */
  601. public function testRightJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void {
  602. $this->queryBuilder->from('data1', 'd1');
  603. $this->queryBuilder->rightJoin(
  604. $fromAlias,
  605. $tableName,
  606. $tableAlias,
  607. $condition
  608. );
  609. $this->assertSame(
  610. $expectedQueryPart,
  611. $this->queryBuilder->getQueryPart('join')
  612. );
  613. $this->assertSame(
  614. 'SELECT FROM ' . $expectedQuery,
  615. $this->queryBuilder->getSQL()
  616. );
  617. }
  618. public function dataSet() {
  619. return [
  620. ['column1', new Literal('value'), null, null, ['`column1` = value'], '`column1` = value'],
  621. ['column1', new Parameter(':param'), null, null, ['`column1` = :param'], '`column1` = :param'],
  622. ['column1', 'column2', null, null, ['`column1` = `column2`'], '`column1` = `column2`'],
  623. ['column1', 'column2', 'column3', new Literal('value'), ['`column1` = `column2`', '`column3` = value'], '`column1` = `column2`, `column3` = value'],
  624. ];
  625. }
  626. /**
  627. * @dataProvider dataSet
  628. *
  629. * @param string $partOne1
  630. * @param string $partOne2
  631. * @param string $partTwo1
  632. * @param string $partTwo2
  633. * @param array $expectedQueryPart
  634. * @param string $expectedQuery
  635. */
  636. public function testSet($partOne1, $partOne2, $partTwo1, $partTwo2, $expectedQueryPart, $expectedQuery): void {
  637. $this->queryBuilder->update('data');
  638. $this->queryBuilder->set($partOne1, $partOne2);
  639. if ($partTwo1 !== null) {
  640. $this->queryBuilder->set($partTwo1, $partTwo2);
  641. }
  642. $this->assertSame(
  643. $expectedQueryPart,
  644. $this->queryBuilder->getQueryPart('set')
  645. );
  646. $this->assertSame(
  647. 'UPDATE `*PREFIX*data` SET ' . $expectedQuery,
  648. $this->queryBuilder->getSQL()
  649. );
  650. }
  651. public function dataWhere() {
  652. return [
  653. [['where1'], new CompositeExpression('AND', ['where1']), 'where1'],
  654. [['where1', 'where2'], new CompositeExpression('AND', ['where1', 'where2']), '(where1) AND (where2)'],
  655. ];
  656. }
  657. /**
  658. * @dataProvider dataWhere
  659. *
  660. * @param array $whereArguments
  661. * @param array $expectedQueryPart
  662. * @param string $expectedQuery
  663. */
  664. public function testWhere($whereArguments, $expectedQueryPart, $expectedQuery): void {
  665. $this->queryBuilder->select('column');
  666. call_user_func_array(
  667. [$this->queryBuilder, 'where'],
  668. $whereArguments
  669. );
  670. $this->assertEquals(
  671. $expectedQueryPart,
  672. $this->queryBuilder->getQueryPart('where')
  673. );
  674. $this->assertSame(
  675. 'SELECT `column` WHERE ' . $expectedQuery,
  676. $this->queryBuilder->getSQL()
  677. );
  678. }
  679. /**
  680. * @dataProvider dataWhere
  681. *
  682. * @param array $whereArguments
  683. * @param array $expectedQueryPart
  684. * @param string $expectedQuery
  685. */
  686. public function testAndWhere($whereArguments, $expectedQueryPart, $expectedQuery): void {
  687. $this->queryBuilder->select('column');
  688. call_user_func_array(
  689. [$this->queryBuilder, 'andWhere'],
  690. $whereArguments
  691. );
  692. $this->assertEquals(
  693. $expectedQueryPart,
  694. $this->queryBuilder->getQueryPart('where')
  695. );
  696. $this->assertSame(
  697. 'SELECT `column` WHERE ' . $expectedQuery,
  698. $this->queryBuilder->getSQL()
  699. );
  700. }
  701. public function dataOrWhere() {
  702. return [
  703. [['where1'], new CompositeExpression('OR', ['where1']), 'where1'],
  704. [['where1', 'where2'], new CompositeExpression('OR', ['where1', 'where2']), '(where1) OR (where2)'],
  705. ];
  706. }
  707. /**
  708. * @dataProvider dataOrWhere
  709. *
  710. * @param array $whereArguments
  711. * @param array $expectedQueryPart
  712. * @param string $expectedQuery
  713. */
  714. public function testOrWhere($whereArguments, $expectedQueryPart, $expectedQuery): void {
  715. $this->queryBuilder->select('column');
  716. call_user_func_array(
  717. [$this->queryBuilder, 'orWhere'],
  718. $whereArguments
  719. );
  720. $this->assertEquals(
  721. $expectedQueryPart,
  722. $this->queryBuilder->getQueryPart('where')
  723. );
  724. $this->assertSame(
  725. 'SELECT `column` WHERE ' . $expectedQuery,
  726. $this->queryBuilder->getSQL()
  727. );
  728. }
  729. public function dataGroupBy() {
  730. return [
  731. [['column1'], ['`column1`'], '`column1`'],
  732. [['column1', 'column2'], ['`column1`', '`column2`'], '`column1`, `column2`'],
  733. ];
  734. }
  735. /**
  736. * @dataProvider dataGroupBy
  737. *
  738. * @param array $groupByArguments
  739. * @param array $expectedQueryPart
  740. * @param string $expectedQuery
  741. */
  742. public function testGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery): void {
  743. $this->queryBuilder->select('column');
  744. call_user_func_array(
  745. [$this->queryBuilder, 'groupBy'],
  746. $groupByArguments
  747. );
  748. $this->assertEquals(
  749. $expectedQueryPart,
  750. $this->queryBuilder->getQueryPart('groupBy')
  751. );
  752. $this->assertSame(
  753. 'SELECT `column` GROUP BY ' . $expectedQuery,
  754. $this->queryBuilder->getSQL()
  755. );
  756. }
  757. public function dataAddGroupBy() {
  758. return [
  759. [['column2'], ['`column1`', '`column2`'], '`column1`, `column2`'],
  760. [['column2', 'column3'], ['`column1`', '`column2`', '`column3`'], '`column1`, `column2`, `column3`'],
  761. ];
  762. }
  763. /**
  764. * @dataProvider dataAddGroupBy
  765. *
  766. * @param array $groupByArguments
  767. * @param array $expectedQueryPart
  768. * @param string $expectedQuery
  769. */
  770. public function testAddGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery): void {
  771. $this->queryBuilder->select('column');
  772. $this->queryBuilder->groupBy('column1');
  773. call_user_func_array(
  774. [$this->queryBuilder, 'addGroupBy'],
  775. $groupByArguments
  776. );
  777. $this->assertEquals(
  778. $expectedQueryPart,
  779. $this->queryBuilder->getQueryPart('groupBy')
  780. );
  781. $this->assertSame(
  782. 'SELECT `column` GROUP BY ' . $expectedQuery,
  783. $this->queryBuilder->getSQL()
  784. );
  785. }
  786. public function dataSetValue() {
  787. return [
  788. ['column', 'value', ['`column`' => 'value'], '(`column`) VALUES(value)'],
  789. ];
  790. }
  791. /**
  792. * @dataProvider dataSetValue
  793. *
  794. * @param string $column
  795. * @param string $value
  796. * @param array $expectedQueryPart
  797. * @param string $expectedQuery
  798. */
  799. public function testSetValue($column, $value, $expectedQueryPart, $expectedQuery): void {
  800. $this->queryBuilder->insert('data');
  801. $this->queryBuilder->setValue($column, $value);
  802. $this->assertEquals(
  803. $expectedQueryPart,
  804. $this->queryBuilder->getQueryPart('values')
  805. );
  806. $this->assertSame(
  807. 'INSERT INTO `*PREFIX*data` ' . $expectedQuery,
  808. $this->queryBuilder->getSQL()
  809. );
  810. }
  811. /**
  812. * @dataProvider dataSetValue
  813. *
  814. * @param string $column
  815. * @param string $value
  816. * @param array $expectedQueryPart
  817. * @param string $expectedQuery
  818. */
  819. public function testValues($column, $value, $expectedQueryPart, $expectedQuery): void {
  820. $this->queryBuilder->insert('data');
  821. $this->queryBuilder->values([
  822. $column => $value,
  823. ]);
  824. $this->assertEquals(
  825. $expectedQueryPart,
  826. $this->queryBuilder->getQueryPart('values')
  827. );
  828. $this->assertSame(
  829. 'INSERT INTO `*PREFIX*data` ' . $expectedQuery,
  830. $this->queryBuilder->getSQL()
  831. );
  832. }
  833. public function dataHaving() {
  834. return [
  835. [['condition1'], new CompositeExpression('AND', ['condition1']), 'HAVING condition1'],
  836. [['condition1', 'condition2'], new CompositeExpression('AND', ['condition1', 'condition2']), 'HAVING (condition1) AND (condition2)'],
  837. [
  838. [new CompositeExpression('OR', ['condition1', 'condition2'])],
  839. new CompositeExpression('OR', ['condition1', 'condition2']),
  840. 'HAVING (condition1) OR (condition2)'
  841. ],
  842. [
  843. [new CompositeExpression('AND', ['condition1', 'condition2'])],
  844. new CompositeExpression('AND', ['condition1', 'condition2']),
  845. 'HAVING (condition1) AND (condition2)'
  846. ],
  847. ];
  848. }
  849. /**
  850. * @dataProvider dataHaving
  851. *
  852. * @param array $havingArguments
  853. * @param array $expectedQueryPart
  854. * @param string $expectedQuery
  855. */
  856. public function testHaving($havingArguments, $expectedQueryPart, $expectedQuery): void {
  857. call_user_func_array(
  858. [$this->queryBuilder, 'having'],
  859. $havingArguments
  860. );
  861. $this->assertEquals(
  862. $expectedQueryPart,
  863. $this->queryBuilder->getQueryPart('having')
  864. );
  865. $this->assertSame(
  866. 'SELECT ' . $expectedQuery,
  867. $this->queryBuilder->getSQL()
  868. );
  869. }
  870. public function dataAndHaving() {
  871. return [
  872. [['condition2'], new CompositeExpression('AND', ['condition1', 'condition2']), 'HAVING (condition1) AND (condition2)'],
  873. [['condition2', 'condition3'], new CompositeExpression('AND', ['condition1', 'condition2', 'condition3']), 'HAVING (condition1) AND (condition2) AND (condition3)'],
  874. [
  875. [new CompositeExpression('OR', ['condition2', 'condition3'])],
  876. new CompositeExpression('AND', ['condition1', new CompositeExpression('OR', ['condition2', 'condition3'])]),
  877. 'HAVING (condition1) AND ((condition2) OR (condition3))'
  878. ],
  879. [
  880. [new CompositeExpression('AND', ['condition2', 'condition3'])],
  881. new CompositeExpression('AND', ['condition1', new CompositeExpression('AND', ['condition2', 'condition3'])]),
  882. 'HAVING (condition1) AND ((condition2) AND (condition3))'
  883. ],
  884. ];
  885. }
  886. /**
  887. * @dataProvider dataAndHaving
  888. *
  889. * @param array $havingArguments
  890. * @param array $expectedQueryPart
  891. * @param string $expectedQuery
  892. */
  893. public function testAndHaving($havingArguments, $expectedQueryPart, $expectedQuery): void {
  894. $this->queryBuilder->having('condition1');
  895. call_user_func_array(
  896. [$this->queryBuilder, 'andHaving'],
  897. $havingArguments
  898. );
  899. $this->assertEquals(
  900. $expectedQueryPart,
  901. $this->queryBuilder->getQueryPart('having')
  902. );
  903. $this->assertSame(
  904. 'SELECT ' . $expectedQuery,
  905. $this->queryBuilder->getSQL()
  906. );
  907. }
  908. public function dataOrHaving() {
  909. return [
  910. [['condition2'], new CompositeExpression('OR', ['condition1', 'condition2']), 'HAVING (condition1) OR (condition2)'],
  911. [['condition2', 'condition3'], new CompositeExpression('OR', ['condition1', 'condition2', 'condition3']), 'HAVING (condition1) OR (condition2) OR (condition3)'],
  912. [
  913. [new CompositeExpression('OR', ['condition2', 'condition3'])],
  914. new CompositeExpression('OR', ['condition1', new CompositeExpression('OR', ['condition2', 'condition3'])]),
  915. 'HAVING (condition1) OR ((condition2) OR (condition3))'
  916. ],
  917. [
  918. [new CompositeExpression('AND', ['condition2', 'condition3'])],
  919. new CompositeExpression('OR', ['condition1', new CompositeExpression('AND', ['condition2', 'condition3'])]),
  920. 'HAVING (condition1) OR ((condition2) AND (condition3))'
  921. ],
  922. ];
  923. }
  924. /**
  925. * @dataProvider dataOrHaving
  926. *
  927. * @param array $havingArguments
  928. * @param array $expectedQueryPart
  929. * @param string $expectedQuery
  930. */
  931. public function testOrHaving($havingArguments, $expectedQueryPart, $expectedQuery): void {
  932. $this->queryBuilder->having('condition1');
  933. call_user_func_array(
  934. [$this->queryBuilder, 'orHaving'],
  935. $havingArguments
  936. );
  937. $this->assertEquals(
  938. $expectedQueryPart,
  939. $this->queryBuilder->getQueryPart('having')
  940. );
  941. $this->assertSame(
  942. 'SELECT ' . $expectedQuery,
  943. $this->queryBuilder->getSQL()
  944. );
  945. }
  946. public function dataOrderBy() {
  947. return [
  948. ['column', null, ['`column` ASC'], 'ORDER BY `column` ASC'],
  949. ['column', 'ASC', ['`column` ASC'], 'ORDER BY `column` ASC'],
  950. ['column', 'DESC', ['`column` DESC'], 'ORDER BY `column` DESC'],
  951. ];
  952. }
  953. /**
  954. * @dataProvider dataOrderBy
  955. *
  956. * @param string $sort
  957. * @param string $order
  958. * @param array $expectedQueryPart
  959. * @param string $expectedQuery
  960. */
  961. public function testOrderBy($sort, $order, $expectedQueryPart, $expectedQuery): void {
  962. $this->queryBuilder->orderBy($sort, $order);
  963. $this->assertEquals(
  964. $expectedQueryPart,
  965. $this->queryBuilder->getQueryPart('orderBy')
  966. );
  967. $this->assertSame(
  968. 'SELECT ' . $expectedQuery,
  969. $this->queryBuilder->getSQL()
  970. );
  971. }
  972. public function dataAddOrderBy() {
  973. return [
  974. ['column2', null, null, ['`column1` ASC', '`column2` ASC'], 'ORDER BY `column1` ASC, `column2` ASC'],
  975. ['column2', null, 'ASC', ['`column1` ASC', '`column2` ASC'], 'ORDER BY `column1` ASC, `column2` ASC'],
  976. ['column2', null, 'DESC', ['`column1` DESC', '`column2` ASC'], 'ORDER BY `column1` DESC, `column2` ASC'],
  977. ['column2', 'ASC', null, ['`column1` ASC', '`column2` ASC'], 'ORDER BY `column1` ASC, `column2` ASC'],
  978. ['column2', 'ASC', 'ASC', ['`column1` ASC', '`column2` ASC'], 'ORDER BY `column1` ASC, `column2` ASC'],
  979. ['column2', 'ASC', 'DESC', ['`column1` DESC', '`column2` ASC'], 'ORDER BY `column1` DESC, `column2` ASC'],
  980. ['column2', 'DESC', null, ['`column1` ASC', '`column2` DESC'], 'ORDER BY `column1` ASC, `column2` DESC'],
  981. ['column2', 'DESC', 'ASC', ['`column1` ASC', '`column2` DESC'], 'ORDER BY `column1` ASC, `column2` DESC'],
  982. ['column2', 'DESC', 'DESC', ['`column1` DESC', '`column2` DESC'], 'ORDER BY `column1` DESC, `column2` DESC'],
  983. ];
  984. }
  985. /**
  986. * @dataProvider dataAddOrderBy
  987. *
  988. * @param string $sort2
  989. * @param string $order2
  990. * @param string $order1
  991. * @param array $expectedQueryPart
  992. * @param string $expectedQuery
  993. */
  994. public function testAddOrderBy($sort2, $order2, $order1, $expectedQueryPart, $expectedQuery): void {
  995. $this->queryBuilder->orderBy('column1', $order1);
  996. $this->queryBuilder->addOrderBy($sort2, $order2);
  997. $this->assertEquals(
  998. $expectedQueryPart,
  999. $this->queryBuilder->getQueryPart('orderBy')
  1000. );
  1001. $this->assertSame(
  1002. 'SELECT ' . $expectedQuery,
  1003. $this->queryBuilder->getSQL()
  1004. );
  1005. }
  1006. public function testGetLastInsertId(): void {
  1007. $qB = $this->connection->getQueryBuilder();
  1008. try {
  1009. $qB->getLastInsertId();
  1010. $this->fail('getLastInsertId() should throw an exception, when being called before insert()');
  1011. } catch (\BadMethodCallException $e) {
  1012. $this->addToAssertionCount(1);
  1013. }
  1014. $qB->insert('properties')
  1015. ->values([
  1016. 'userid' => $qB->expr()->literal('testFirstResult'),
  1017. 'propertypath' => $qB->expr()->literal('testing'),
  1018. 'propertyname' => $qB->expr()->literal('testing'),
  1019. 'propertyvalue' => $qB->expr()->literal('testing'),
  1020. ])
  1021. ->execute();
  1022. $actual = $qB->getLastInsertId();
  1023. $this->assertNotNull($actual);
  1024. $this->assertIsInt($actual);
  1025. $this->assertEquals($this->connection->lastInsertId('*PREFIX*properties'), $actual);
  1026. $qB->delete('properties')
  1027. ->where($qB->expr()->eq('userid', $qB->expr()->literal('testFirstResult')))
  1028. ->execute();
  1029. try {
  1030. $qB->getLastInsertId();
  1031. $this->fail('getLastInsertId() should throw an exception, when being called after delete()');
  1032. } catch (\BadMethodCallException $e) {
  1033. $this->addToAssertionCount(1);
  1034. }
  1035. }
  1036. public function dataGetTableName() {
  1037. $config = $this->createMock(SystemConfig::class);
  1038. $logger = $this->createMock(LoggerInterface::class);
  1039. $qb = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
  1040. return [
  1041. ['*PREFIX*table', null, '`*PREFIX*table`'],
  1042. ['*PREFIX*table', true, '`*PREFIX*table`'],
  1043. ['*PREFIX*table', false, '`*PREFIX*table`'],
  1044. ['table', null, '`*PREFIX*table`'],
  1045. ['table', true, '`*PREFIX*table`'],
  1046. ['table', false, '`table`'],
  1047. [$qb->createFunction('(' . $qb->select('*')->from('table')->getSQL() . ')'), null, '(SELECT * FROM `*PREFIX*table`)'],
  1048. [$qb->createFunction('(' . $qb->select('*')->from('table')->getSQL() . ')'), true, '(SELECT * FROM `*PREFIX*table`)'],
  1049. [$qb->createFunction('(' . $qb->select('*')->from('table')->getSQL() . ')'), false, '(SELECT * FROM `*PREFIX*table`)'],
  1050. ];
  1051. }
  1052. /**
  1053. * @dataProvider dataGetTableName
  1054. *
  1055. * @param string|IQueryFunction $tableName
  1056. * @param bool $automatic
  1057. * @param string $expected
  1058. */
  1059. public function testGetTableName($tableName, $automatic, $expected): void {
  1060. if ($automatic !== null) {
  1061. $this->queryBuilder->automaticTablePrefix($automatic);
  1062. }
  1063. $this->assertSame(
  1064. $expected,
  1065. $this->queryBuilder->getTableName($tableName)
  1066. );
  1067. }
  1068. public function dataGetColumnName() {
  1069. return [
  1070. ['column', '', '`column`'],
  1071. ['column', 'a', '`a`.`column`'],
  1072. ];
  1073. }
  1074. /**
  1075. * @dataProvider dataGetColumnName
  1076. * @param string $column
  1077. * @param string $prefix
  1078. * @param string $expected
  1079. */
  1080. public function testGetColumnName($column, $prefix, $expected): void {
  1081. $this->assertSame(
  1082. $expected,
  1083. $this->queryBuilder->getColumnName($column, $prefix)
  1084. );
  1085. }
  1086. private function getConnection(): IDBConnection {
  1087. $connection = $this->createMock(IDBConnection::class);
  1088. $connection->method('executeStatement')
  1089. ->willReturn(3);
  1090. $connection->method('executeQuery')
  1091. ->willReturn($this->createMock(IResult::class));
  1092. return $connection;
  1093. }
  1094. public function testExecuteWithoutLogger(): void {
  1095. $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
  1096. $queryBuilder
  1097. ->method('getSQL')
  1098. ->willReturn('');
  1099. $queryBuilder
  1100. ->method('getParameters')
  1101. ->willReturn([]);
  1102. $queryBuilder
  1103. ->method('getParameterTypes')
  1104. ->willReturn([]);
  1105. $queryBuilder
  1106. ->method('getType')
  1107. ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE);
  1108. $this->logger
  1109. ->expects($this->never())
  1110. ->method('debug');
  1111. $this->config
  1112. ->expects($this->once())
  1113. ->method('getValue')
  1114. ->with('log_query', false)
  1115. ->willReturn(false);
  1116. $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
  1117. $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
  1118. $this->assertEquals(3, $this->queryBuilder->execute());
  1119. }
  1120. public function testExecuteWithLoggerAndNamedArray(): void {
  1121. $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
  1122. $queryBuilder
  1123. ->expects($this->any())
  1124. ->method('getParameters')
  1125. ->willReturn([
  1126. 'foo' => 'bar',
  1127. 'key' => 'value',
  1128. ]);
  1129. $queryBuilder
  1130. ->method('getParameterTypes')
  1131. ->willReturn([
  1132. 'foo' => IQueryBuilder::PARAM_STR,
  1133. 'key' => IQueryBuilder::PARAM_STR,
  1134. ]);
  1135. $queryBuilder
  1136. ->method('getType')
  1137. ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE);
  1138. $queryBuilder
  1139. ->expects($this->any())
  1140. ->method('getSQL')
  1141. ->willReturn('UPDATE FOO SET bar = 1 WHERE BAR = ?');
  1142. $this->logger
  1143. ->expects($this->once())
  1144. ->method('debug')
  1145. ->with(
  1146. 'DB QueryBuilder: \'{query}\' with parameters: {params}',
  1147. [
  1148. 'query' => 'UPDATE FOO SET bar = 1 WHERE BAR = ?',
  1149. 'params' => 'foo => \'bar\', key => \'value\'',
  1150. 'app' => 'core',
  1151. ]
  1152. );
  1153. $this->config
  1154. ->expects($this->once())
  1155. ->method('getValue')
  1156. ->with('log_query', false)
  1157. ->willReturn(true);
  1158. $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
  1159. $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
  1160. $this->assertEquals(3, $this->queryBuilder->execute());
  1161. }
  1162. public function testExecuteWithLoggerAndUnnamedArray(): void {
  1163. $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
  1164. $queryBuilder
  1165. ->expects($this->any())
  1166. ->method('getParameters')
  1167. ->willReturn(['Bar']);
  1168. $queryBuilder
  1169. ->method('getParameterTypes')
  1170. ->willReturn([IQueryBuilder::PARAM_STR]);
  1171. $queryBuilder
  1172. ->method('getType')
  1173. ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE);
  1174. $queryBuilder
  1175. ->expects($this->any())
  1176. ->method('getSQL')
  1177. ->willReturn('UPDATE FOO SET bar = false WHERE BAR = ?');
  1178. $this->logger
  1179. ->expects($this->once())
  1180. ->method('debug')
  1181. ->with(
  1182. 'DB QueryBuilder: \'{query}\' with parameters: {params}',
  1183. [
  1184. 'query' => 'UPDATE FOO SET bar = false WHERE BAR = ?',
  1185. 'params' => '0 => \'Bar\'',
  1186. 'app' => 'core',
  1187. ]
  1188. );
  1189. $this->config
  1190. ->expects($this->once())
  1191. ->method('getValue')
  1192. ->with('log_query', false)
  1193. ->willReturn(true);
  1194. $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
  1195. $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
  1196. $this->assertEquals(3, $this->queryBuilder->execute());
  1197. }
  1198. public function testExecuteWithLoggerAndNoParams(): void {
  1199. $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
  1200. $queryBuilder
  1201. ->expects($this->any())
  1202. ->method('getParameters')
  1203. ->willReturn([]);
  1204. $queryBuilder
  1205. ->method('getParameterTypes')
  1206. ->willReturn([]);
  1207. $queryBuilder
  1208. ->method('getType')
  1209. ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE);
  1210. $queryBuilder
  1211. ->expects($this->any())
  1212. ->method('getSQL')
  1213. ->willReturn('UPDATE FOO SET bar = false WHERE BAR = ?');
  1214. $this->logger
  1215. ->expects($this->once())
  1216. ->method('debug')
  1217. ->with(
  1218. 'DB QueryBuilder: \'{query}\'',
  1219. [
  1220. 'query' => 'UPDATE FOO SET bar = false WHERE BAR = ?',
  1221. 'app' => 'core',
  1222. ]
  1223. );
  1224. $this->config
  1225. ->expects($this->once())
  1226. ->method('getValue')
  1227. ->with('log_query', false)
  1228. ->willReturn(true);
  1229. $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
  1230. $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
  1231. $this->assertEquals(3, $this->queryBuilder->execute());
  1232. }
  1233. public function testExecuteWithParameterTooLarge(): void {
  1234. $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
  1235. $p = array_fill(0, 1001, 'foo');
  1236. $queryBuilder
  1237. ->expects($this->any())
  1238. ->method('getParameters')
  1239. ->willReturn([$p]);
  1240. $queryBuilder
  1241. ->method('getParameterTypes')
  1242. ->willReturn([IQueryBuilder::PARAM_STR_ARRAY]);
  1243. $queryBuilder
  1244. ->expects($this->any())
  1245. ->method('getSQL')
  1246. ->willReturn('SELECT * FROM FOO WHERE BAR IN (?)');
  1247. $this->logger
  1248. ->expects($this->once())
  1249. ->method('error')
  1250. ->willReturnCallback(function ($message, $parameters) {
  1251. $this->assertInstanceOf(QueryException::class, $parameters['exception']);
  1252. $this->assertSame(
  1253. 'More than 1000 expressions in a list are not allowed on Oracle.',
  1254. $message
  1255. );
  1256. });
  1257. $this->config
  1258. ->expects($this->once())
  1259. ->method('getValue')
  1260. ->with('log_query', false)
  1261. ->willReturn(false);
  1262. $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
  1263. $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
  1264. $this->queryBuilder->execute();
  1265. }
  1266. public function testExecuteWithParametersTooMany(): void {
  1267. $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
  1268. $p = array_fill(0, 999, 'foo');
  1269. $queryBuilder
  1270. ->expects($this->any())
  1271. ->method('getParameters')
  1272. ->willReturn(array_fill(0, 66, $p));
  1273. $queryBuilder
  1274. ->method('getParameterTypes')
  1275. ->willReturn([IQueryBuilder::PARAM_STR_ARRAY]);
  1276. $queryBuilder
  1277. ->expects($this->any())
  1278. ->method('getSQL')
  1279. ->willReturn('SELECT * FROM FOO WHERE BAR IN (?) OR BAR IN (?)');
  1280. $this->logger
  1281. ->expects($this->once())
  1282. ->method('error')
  1283. ->willReturnCallback(function ($message, $parameters) {
  1284. $this->assertInstanceOf(QueryException::class, $parameters['exception']);
  1285. $this->assertSame(
  1286. 'The number of parameters must not exceed 65535. Restriction by PostgreSQL.',
  1287. $message
  1288. );
  1289. });
  1290. $this->config
  1291. ->expects($this->once())
  1292. ->method('getValue')
  1293. ->with('log_query', false)
  1294. ->willReturn(false);
  1295. $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
  1296. $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
  1297. $this->queryBuilder->execute();
  1298. }
  1299. }