Add DROP INDEX support to DatabaseSqlite::replaceVars method
[lhc/web/wiklou.git] / tests / phpunit / includes / db / DatabaseSQLTest.php
1 <?php
2
3 /**
4 * Test the abstract database layer
5 * This is a non DBMS depending test.
6 */
7 class DatabaseSQLTest extends MediaWikiTestCase {
8
9 private $database;
10
11 protected function setUp() {
12 parent::setUp();
13 $this->database = new DatabaseTestHelper( __CLASS__ );
14 }
15
16 protected function assertLastSql( $sqlText ) {
17 $this->assertEquals(
18 $this->database->getLastSqls(),
19 $sqlText
20 );
21 }
22
23 /**
24 * @dataProvider provideSelect
25 */
26 function testSelect( $sql, $sqlText ) {
27 $this->database->select(
28 $sql['tables'],
29 $sql['fields'],
30 isset( $sql['conds'] ) ? $sql['conds'] : array(),
31 __METHOD__,
32 isset( $sql['options'] ) ? $sql['options'] : array(),
33 isset( $sql['join_conds'] ) ? $sql['join_conds'] : array()
34 );
35 $this->assertLastSql( $sqlText );
36 }
37
38 public static function provideSelect() {
39 return array(
40 array(
41 array(
42 'tables' => 'table',
43 'fields' => array( 'field', 'alias' => 'field2' ),
44 'conds' => array( 'alias' => 'text' ),
45 ),
46 "SELECT field,field2 AS alias " .
47 "FROM table " .
48 "WHERE alias = 'text'"
49 ),
50 array(
51 array(
52 'tables' => 'table',
53 'fields' => array( 'field', 'alias' => 'field2' ),
54 'conds' => array( 'alias' => 'text' ),
55 'options' => array( 'LIMIT' => 1, 'ORDER BY' => 'field' ),
56 ),
57 "SELECT field,field2 AS alias " .
58 "FROM table " .
59 "WHERE alias = 'text' " .
60 "ORDER BY field " .
61 "LIMIT 1"
62 ),
63 array(
64 array(
65 'tables' => array( 'table', 't2' => 'table2' ),
66 'fields' => array( 'tid', 'field', 'alias' => 'field2', 't2.id' ),
67 'conds' => array( 'alias' => 'text' ),
68 'options' => array( 'LIMIT' => 1, 'ORDER BY' => 'field' ),
69 'join_conds' => array( 't2' => array(
70 'LEFT JOIN', 'tid = t2.id'
71 ) ),
72 ),
73 "SELECT tid,field,field2 AS alias,t2.id " .
74 "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
75 "WHERE alias = 'text' " .
76 "ORDER BY field " .
77 "LIMIT 1"
78 ),
79 array(
80 array(
81 'tables' => array( 'table', 't2' => 'table2' ),
82 'fields' => array( 'tid', 'field', 'alias' => 'field2', 't2.id' ),
83 'conds' => array( 'alias' => 'text' ),
84 'options' => array( 'LIMIT' => 1, 'GROUP BY' => 'field', 'HAVING' => 'COUNT(*) > 1' ),
85 'join_conds' => array( 't2' => array(
86 'LEFT JOIN', 'tid = t2.id'
87 ) ),
88 ),
89 "SELECT tid,field,field2 AS alias,t2.id " .
90 "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
91 "WHERE alias = 'text' " .
92 "GROUP BY field HAVING COUNT(*) > 1 " .
93 "LIMIT 1"
94 ),
95 array(
96 array(
97 'tables' => array( 'table', 't2' => 'table2' ),
98 'fields' => array( 'tid', 'field', 'alias' => 'field2', 't2.id' ),
99 'conds' => array( 'alias' => 'text' ),
100 'options' => array( 'LIMIT' => 1, 'GROUP BY' => array( 'field', 'field2' ), 'HAVING' => array( 'COUNT(*) > 1', 'field' => 1 ) ),
101 'join_conds' => array( 't2' => array(
102 'LEFT JOIN', 'tid = t2.id'
103 ) ),
104 ),
105 "SELECT tid,field,field2 AS alias,t2.id " .
106 "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
107 "WHERE alias = 'text' " .
108 "GROUP BY field,field2 HAVING (COUNT(*) > 1) AND field = '1' " .
109 "LIMIT 1"
110 ),
111 array(
112 array(
113 'tables' => array( 'table' ),
114 'fields' => array( 'alias' => 'field' ),
115 'conds' => array( 'alias' => array( 1, 2, 3, 4 ) ),
116 ),
117 "SELECT field AS alias " .
118 "FROM table " .
119 "WHERE alias IN ('1','2','3','4')"
120 ),
121 );
122 }
123
124 /**
125 * @dataProvider provideUpdate
126 */
127 function testUpdate( $sql, $sqlText ) {
128 $this->database->update(
129 $sql['table'],
130 $sql['values'],
131 $sql['conds'],
132 __METHOD__,
133 isset( $sql['options'] ) ? $sql['options'] : array()
134 );
135 $this->assertLastSql( $sqlText );
136 }
137
138 public static function provideUpdate() {
139 return array(
140 array(
141 array(
142 'table' => 'table',
143 'values' => array( 'field' => 'text', 'field2' => 'text2' ),
144 'conds' => array( 'alias' => 'text' ),
145 ),
146 "UPDATE table " .
147 "SET field = 'text'" .
148 ",field2 = 'text2' " .
149 "WHERE alias = 'text'"
150 ),
151 array(
152 array(
153 'table' => 'table',
154 'values' => array( 'field = other', 'field2' => 'text2' ),
155 'conds' => array( 'id' => '1' ),
156 ),
157 "UPDATE table " .
158 "SET field = other" .
159 ",field2 = 'text2' " .
160 "WHERE id = '1'"
161 ),
162 array(
163 array(
164 'table' => 'table',
165 'values' => array( 'field = other', 'field2' => 'text2' ),
166 'conds' => '*',
167 ),
168 "UPDATE table " .
169 "SET field = other" .
170 ",field2 = 'text2'"
171 ),
172 );
173 }
174
175 /**
176 * @dataProvider provideDelete
177 */
178 function testDelete( $sql, $sqlText ) {
179 $this->database->delete(
180 $sql['table'],
181 $sql['conds'],
182 __METHOD__
183 );
184 $this->assertLastSql( $sqlText );
185 }
186
187 public static function provideDelete() {
188 return array(
189 array(
190 array(
191 'table' => 'table',
192 'conds' => array( 'alias' => 'text' ),
193 ),
194 "DELETE FROM table " .
195 "WHERE alias = 'text'"
196 ),
197 array(
198 array(
199 'table' => 'table',
200 'conds' => '*',
201 ),
202 "DELETE FROM table"
203 ),
204 );
205 }
206
207 /**
208 * @dataProvider provideUpsert
209 */
210 function testUpsert( $sql, $sqlText ) {
211 $this->database->upsert(
212 $sql['table'],
213 $sql['rows'],
214 $sql['uniqueIndexes'],
215 $sql['set'],
216 __METHOD__
217 );
218 $this->assertLastSql( $sqlText );
219 }
220
221 public static function provideUpsert() {
222 return array(
223 array(
224 array(
225 'table' => 'upsert_table',
226 'rows' => array( 'field' => 'text', 'field2' => 'text2' ),
227 'uniqueIndexes' => array( 'field' ),
228 'set' => array( 'field' => 'set' ),
229 ),
230 "BEGIN; " .
231 "UPDATE upsert_table " .
232 "SET field = 'set' " .
233 "WHERE ((field = 'text')); " .
234 "INSERT IGNORE INTO upsert_table " .
235 "(field,field2) " .
236 "VALUES ('text','text2'); " .
237 "COMMIT"
238 ),
239 );
240 }
241
242 /**
243 * @dataProvider provideDeleteJoin
244 */
245 function testDeleteJoin( $sql, $sqlText ) {
246 $this->database->deleteJoin(
247 $sql['delTable'],
248 $sql['joinTable'],
249 $sql['delVar'],
250 $sql['joinVar'],
251 $sql['conds'],
252 __METHOD__
253 );
254 $this->assertLastSql( $sqlText );
255 }
256
257 public static function provideDeleteJoin() {
258 return array(
259 array(
260 array(
261 'delTable' => 'table',
262 'joinTable' => 'table_join',
263 'delVar' => 'field',
264 'joinVar' => 'field_join',
265 'conds' => array( 'alias' => 'text' ),
266 ),
267 "DELETE FROM table " .
268 "WHERE field IN (" .
269 "SELECT field_join FROM table_join WHERE alias = 'text'" .
270 ")"
271 ),
272 array(
273 array(
274 'delTable' => 'table',
275 'joinTable' => 'table_join',
276 'delVar' => 'field',
277 'joinVar' => 'field_join',
278 'conds' => '*',
279 ),
280 "DELETE FROM table " .
281 "WHERE field IN (" .
282 "SELECT field_join FROM table_join " .
283 ")"
284 ),
285 );
286 }
287
288 /**
289 * @dataProvider provideInsert
290 */
291 function testInsert( $sql, $sqlText ) {
292 $this->database->insert(
293 $sql['table'],
294 $sql['rows'],
295 __METHOD__,
296 isset( $sql['options'] ) ? $sql['options'] : array()
297 );
298 $this->assertLastSql( $sqlText );
299 }
300
301 public static function provideInsert() {
302 return array(
303 array(
304 array(
305 'table' => 'table',
306 'rows' => array( 'field' => 'text', 'field2' => 2 ),
307 ),
308 "INSERT INTO table " .
309 "(field,field2) " .
310 "VALUES ('text','2')"
311 ),
312 array(
313 array(
314 'table' => 'table',
315 'rows' => array( 'field' => 'text', 'field2' => 2 ),
316 'options' => 'IGNORE',
317 ),
318 "INSERT IGNORE INTO table " .
319 "(field,field2) " .
320 "VALUES ('text','2')"
321 ),
322 array(
323 array(
324 'table' => 'table',
325 'rows' => array(
326 array( 'field' => 'text', 'field2' => 2 ),
327 array( 'field' => 'multi', 'field2' => 3 ),
328 ),
329 'options' => 'IGNORE',
330 ),
331 "INSERT IGNORE INTO table " .
332 "(field,field2) " .
333 "VALUES " .
334 "('text','2')," .
335 "('multi','3')"
336 ),
337 );
338 }
339
340 /**
341 * @dataProvider provideInsertSelect
342 */
343 function testInsertSelect( $sql, $sqlText ) {
344 $this->database->insertSelect(
345 $sql['destTable'],
346 $sql['srcTable'],
347 $sql['varMap'],
348 $sql['conds'],
349 __METHOD__,
350 isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : array(),
351 isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : array()
352 );
353 $this->assertLastSql( $sqlText );
354 }
355
356 public static function provideInsertSelect() {
357 return array(
358 array(
359 array(
360 'destTable' => 'insert_table',
361 'srcTable' => 'select_table',
362 'varMap' => array( 'field_insert' => 'field_select', 'field' => 'field2' ),
363 'conds' => '*',
364 ),
365 "INSERT INTO insert_table " .
366 "(field_insert,field) " .
367 "SELECT field_select,field2 " .
368 "FROM select_table"
369 ),
370 array(
371 array(
372 'destTable' => 'insert_table',
373 'srcTable' => 'select_table',
374 'varMap' => array( 'field_insert' => 'field_select', 'field' => 'field2' ),
375 'conds' => array( 'field' => 2 ),
376 ),
377 "INSERT INTO insert_table " .
378 "(field_insert,field) " .
379 "SELECT field_select,field2 " .
380 "FROM select_table " .
381 "WHERE field = '2'"
382 ),
383 array(
384 array(
385 'destTable' => 'insert_table',
386 'srcTable' => 'select_table',
387 'varMap' => array( 'field_insert' => 'field_select', 'field' => 'field2' ),
388 'conds' => array( 'field' => 2 ),
389 'insertOptions' => 'IGNORE',
390 'selectOptions' => array( 'ORDER BY' => 'field' ),
391 ),
392 "INSERT IGNORE INTO insert_table " .
393 "(field_insert,field) " .
394 "SELECT field_select,field2 " .
395 "FROM select_table " .
396 "WHERE field = '2' " .
397 "ORDER BY field"
398 ),
399 );
400 }
401
402 /**
403 * @dataProvider provideReplace
404 */
405 function testReplace( $sql, $sqlText ) {
406 $this->database->replace(
407 $sql['table'],
408 $sql['uniqueIndexes'],
409 $sql['rows'],
410 __METHOD__
411 );
412 $this->assertLastSql( $sqlText );
413 }
414
415 public static function provideReplace() {
416 return array(
417 array(
418 array(
419 'table' => 'replace_table',
420 'uniqueIndexes' => array( 'field' ),
421 'rows' => array( 'field' => 'text', 'field2' => 'text2' ),
422 ),
423 "DELETE FROM replace_table " .
424 "WHERE ( field='text' ); " .
425 "INSERT INTO replace_table " .
426 "(field,field2) " .
427 "VALUES ('text','text2')"
428 ),
429 array(
430 array(
431 'table' => 'module_deps',
432 'uniqueIndexes' => array( array( 'md_module', 'md_skin' ) ),
433 'rows' => array(
434 'md_module' => 'module',
435 'md_skin' => 'skin',
436 'md_deps' => 'deps',
437 ),
438 ),
439 "DELETE FROM module_deps " .
440 "WHERE ( md_module='module' AND md_skin='skin' ); " .
441 "INSERT INTO module_deps " .
442 "(md_module,md_skin,md_deps) " .
443 "VALUES ('module','skin','deps')"
444 ),
445 array(
446 array(
447 'table' => 'module_deps',
448 'uniqueIndexes' => array( array( 'md_module', 'md_skin' ) ),
449 'rows' => array(
450 array(
451 'md_module' => 'module',
452 'md_skin' => 'skin',
453 'md_deps' => 'deps',
454 ), array(
455 'md_module' => 'module2',
456 'md_skin' => 'skin2',
457 'md_deps' => 'deps2',
458 ),
459 ),
460 ),
461 "DELETE FROM module_deps " .
462 "WHERE ( md_module='module' AND md_skin='skin' ); " .
463 "INSERT INTO module_deps " .
464 "(md_module,md_skin,md_deps) " .
465 "VALUES ('module','skin','deps'); " .
466 "DELETE FROM module_deps " .
467 "WHERE ( md_module='module2' AND md_skin='skin2' ); " .
468 "INSERT INTO module_deps " .
469 "(md_module,md_skin,md_deps) " .
470 "VALUES ('module2','skin2','deps2')"
471 ),
472 array(
473 array(
474 'table' => 'module_deps',
475 'uniqueIndexes' => array( 'md_module', 'md_skin' ),
476 'rows' => array(
477 array(
478 'md_module' => 'module',
479 'md_skin' => 'skin',
480 'md_deps' => 'deps',
481 ), array(
482 'md_module' => 'module2',
483 'md_skin' => 'skin2',
484 'md_deps' => 'deps2',
485 ),
486 ),
487 ),
488 "DELETE FROM module_deps " .
489 "WHERE ( md_module='module' ) OR ( md_skin='skin' ); " .
490 "INSERT INTO module_deps " .
491 "(md_module,md_skin,md_deps) " .
492 "VALUES ('module','skin','deps'); " .
493 "DELETE FROM module_deps " .
494 "WHERE ( md_module='module2' ) OR ( md_skin='skin2' ); " .
495 "INSERT INTO module_deps " .
496 "(md_module,md_skin,md_deps) " .
497 "VALUES ('module2','skin2','deps2')"
498 ),
499 array(
500 array(
501 'table' => 'module_deps',
502 'uniqueIndexes' => array(),
503 'rows' => array(
504 'md_module' => 'module',
505 'md_skin' => 'skin',
506 'md_deps' => 'deps',
507 ),
508 ),
509 "INSERT INTO module_deps " .
510 "(md_module,md_skin,md_deps) " .
511 "VALUES ('module','skin','deps')"
512 ),
513 );
514 }
515
516 /**
517 * @dataProvider provideNativeReplace
518 */
519 function testNativeReplace( $sql, $sqlText ) {
520 $this->database->nativeReplace(
521 $sql['table'],
522 $sql['rows'],
523 __METHOD__
524 );
525 $this->assertLastSql( $sqlText );
526 }
527
528 public static function provideNativeReplace() {
529 return array(
530 array(
531 array(
532 'table' => 'replace_table',
533 'rows' => array( 'field' => 'text', 'field2' => 'text2' ),
534 ),
535 "REPLACE INTO replace_table " .
536 "(field,field2) " .
537 "VALUES ('text','text2')"
538 ),
539 );
540 }
541
542 /**
543 * @dataProvider provideConditional
544 */
545 function testConditional( $sql, $sqlText ) {
546 $this->assertEquals( trim( $this->database->conditional(
547 $sql['conds'],
548 $sql['true'],
549 $sql['false']
550 ) ), $sqlText );
551 }
552
553 public static function provideConditional() {
554 return array(
555 array(
556 array(
557 'conds' => array( 'field' => 'text' ),
558 'true' => 1,
559 'false' => 'NULL',
560 ),
561 "(CASE WHEN field = 'text' THEN 1 ELSE NULL END)"
562 ),
563 array(
564 array(
565 'conds' => array( 'field' => 'text', 'field2' => 'anothertext' ),
566 'true' => 1,
567 'false' => 'NULL',
568 ),
569 "(CASE WHEN field = 'text' AND field2 = 'anothertext' THEN 1 ELSE NULL END)"
570 ),
571 array(
572 array(
573 'conds' => 'field=1',
574 'true' => 1,
575 'false' => 'NULL',
576 ),
577 "(CASE WHEN field=1 THEN 1 ELSE NULL END)"
578 ),
579 );
580 }
581
582 /**
583 * @dataProvider provideBuildConcat
584 */
585 function testBuildConcat( $stringList, $sqlText ) {
586 $this->assertEquals( trim( $this->database->buildConcat(
587 $stringList
588 ) ), $sqlText );
589 }
590
591 public static function provideBuildConcat() {
592 return array(
593 array(
594 array( 'field', 'field2' ),
595 "CONCAT(field,field2)"
596 ),
597 array(
598 array( "'test'", 'field2' ),
599 "CONCAT('test',field2)"
600 ),
601 );
602 }
603
604 /**
605 * @dataProvider provideBuildLike
606 */
607 function testBuildLike( $array, $sqlText ) {
608 $this->assertEquals( trim( $this->database->buildLike(
609 $array
610 ) ), $sqlText );
611 }
612
613 public static function provideBuildLike() {
614 return array(
615 array(
616 'text',
617 "LIKE 'text'"
618 ),
619 array(
620 array( 'text', new LikeMatch( '%' ) ),
621 "LIKE 'text%'"
622 ),
623 array(
624 array( 'text', new LikeMatch( '%' ), 'text2' ),
625 "LIKE 'text%text2'"
626 ),
627 array(
628 array( 'text', new LikeMatch( '_' ) ),
629 "LIKE 'text_'"
630 ),
631 );
632 }
633
634 /**
635 * @dataProvider provideUnionQueries
636 */
637 function testUnionQueries( $sql, $sqlText ) {
638 $this->assertEquals( trim( $this->database->unionQueries(
639 $sql['sqls'],
640 $sql['all']
641 ) ), $sqlText );
642 }
643
644 public static function provideUnionQueries() {
645 return array(
646 array(
647 array(
648 'sqls' => array( 'RAW SQL', 'RAW2SQL' ),
649 'all' => true,
650 ),
651 "(RAW SQL) UNION ALL (RAW2SQL)"
652 ),
653 array(
654 array(
655 'sqls' => array( 'RAW SQL', 'RAW2SQL' ),
656 'all' => false,
657 ),
658 "(RAW SQL) UNION (RAW2SQL)"
659 ),
660 array(
661 array(
662 'sqls' => array( 'RAW SQL', 'RAW2SQL', 'RAW3SQL' ),
663 'all' => false,
664 ),
665 "(RAW SQL) UNION (RAW2SQL) UNION (RAW3SQL)"
666 ),
667 );
668 }
669
670 function testTransactionCommit() {
671 $this->database->begin( __METHOD__ );
672 $this->database->commit( __METHOD__ );
673 $this->assertLastSql( 'BEGIN; COMMIT' );
674 }
675
676 function testTransactionRollback() {
677 $this->database->begin( __METHOD__ );
678 $this->database->rollback( __METHOD__ );
679 $this->assertLastSql( 'BEGIN; ROLLBACK' );
680 }
681
682 function testDropTable() {
683 $this->database->setExistingTables( array( 'table' ) );
684 $this->database->dropTable( 'table', __METHOD__ );
685 $this->assertLastSql( 'DROP TABLE table' );
686 }
687
688 function testDropNonExistingTable() {
689 $this->assertFalse(
690 $this->database->dropTable( 'non_existing', __METHOD__ )
691 );
692 }
693 }