MediaWiki REL1_30
DatabaseSQLTest.php
Go to the documentation of this file.
1<?php
2
4
9class DatabaseSQLTest extends PHPUnit_Framework_TestCase {
11 private $database;
12
13 protected function setUp() {
14 parent::setUp();
15 $this->database = new DatabaseTestHelper( __CLASS__, [ 'cliMode' => true ] );
16 }
17
18 protected function assertLastSql( $sqlText ) {
19 $this->assertEquals(
20 $sqlText,
21 $this->database->getLastSqls()
22 );
23 }
24
25 protected function assertLastSqlDb( $sqlText, DatabaseTestHelper $db ) {
26 $this->assertEquals( $sqlText, $db->getLastSqls() );
27 }
28
40 public function testSelect( $sql, $sqlText ) {
41 $this->database->select(
42 $sql['tables'],
43 $sql['fields'],
44 isset( $sql['conds'] ) ? $sql['conds'] : [],
45 __METHOD__,
46 isset( $sql['options'] ) ? $sql['options'] : [],
47 isset( $sql['join_conds'] ) ? $sql['join_conds'] : []
48 );
49 $this->assertLastSql( $sqlText );
50 }
51
52 public static function provideSelect() {
53 return [
54 [
55 [
56 'tables' => 'table',
57 'fields' => [ 'field', 'alias' => 'field2' ],
58 'conds' => [ 'alias' => 'text' ],
59 ],
60 "SELECT field,field2 AS alias " .
61 "FROM table " .
62 "WHERE alias = 'text'"
63 ],
64 [
65 [
66 // 'tables' with space prepended indicates pre-escaped table name
67 'tables' => ' table LEFT JOIN table2',
68 'fields' => [ 'field' ],
69 'conds' => [ 'field' => 'text' ],
70 ],
71 "SELECT field FROM table LEFT JOIN table2 WHERE field = 'text'"
72 ],
73 [
74 [
75 // Empty 'tables' is allowed
76 'tables' => '',
77 'fields' => [ 'SPECIAL_QUERY()' ],
78 ],
79 "SELECT SPECIAL_QUERY()"
80 ],
81 [
82 [
83 'tables' => 'table',
84 'fields' => [ 'field', 'alias' => 'field2' ],
85 'conds' => [ 'alias' => 'text' ],
86 'options' => [ 'LIMIT' => 1, 'ORDER BY' => 'field' ],
87 ],
88 "SELECT field,field2 AS alias " .
89 "FROM table " .
90 "WHERE alias = 'text' " .
91 "ORDER BY field " .
92 "LIMIT 1"
93 ],
94 [
95 [
96 'tables' => [ 'table', 't2' => 'table2' ],
97 'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
98 'conds' => [ 'alias' => 'text' ],
99 'options' => [ 'LIMIT' => 1, 'ORDER BY' => 'field' ],
100 'join_conds' => [ 't2' => [
101 'LEFT JOIN', 'tid = t2.id'
102 ] ],
103 ],
104 "SELECT tid,field,field2 AS alias,t2.id " .
105 "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
106 "WHERE alias = 'text' " .
107 "ORDER BY field " .
108 "LIMIT 1"
109 ],
110 [
111 [
112 'tables' => [ 'table', 't2' => 'table2' ],
113 'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
114 'conds' => [ 'alias' => 'text' ],
115 'options' => [ 'LIMIT' => 1, 'GROUP BY' => 'field', 'HAVING' => 'COUNT(*) > 1' ],
116 'join_conds' => [ 't2' => [
117 'LEFT JOIN', 'tid = t2.id'
118 ] ],
119 ],
120 "SELECT tid,field,field2 AS alias,t2.id " .
121 "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
122 "WHERE alias = 'text' " .
123 "GROUP BY field HAVING COUNT(*) > 1 " .
124 "LIMIT 1"
125 ],
126 [
127 [
128 'tables' => [ 'table', 't2' => 'table2' ],
129 'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
130 'conds' => [ 'alias' => 'text' ],
131 'options' => [
132 'LIMIT' => 1,
133 'GROUP BY' => [ 'field', 'field2' ],
134 'HAVING' => [ 'COUNT(*) > 1', 'field' => 1 ]
135 ],
136 'join_conds' => [ 't2' => [
137 'LEFT JOIN', 'tid = t2.id'
138 ] ],
139 ],
140 "SELECT tid,field,field2 AS alias,t2.id " .
141 "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
142 "WHERE alias = 'text' " .
143 "GROUP BY field,field2 HAVING (COUNT(*) > 1) AND field = '1' " .
144 "LIMIT 1"
145 ],
146 [
147 [
148 'tables' => [ 'table' ],
149 'fields' => [ 'alias' => 'field' ],
150 'conds' => [ 'alias' => [ 1, 2, 3, 4 ] ],
151 ],
152 "SELECT field AS alias " .
153 "FROM table " .
154 "WHERE alias IN ('1','2','3','4')"
155 ],
156 [
157 [
158 'tables' => 'table',
159 'fields' => [ 'field' ],
160 'options' => [ 'USE INDEX' => [ 'table' => 'X' ] ],
161 ],
162 // No-op by default
163 "SELECT field FROM table"
164 ],
165 [
166 [
167 'tables' => 'table',
168 'fields' => [ 'field' ],
169 'options' => [ 'IGNORE INDEX' => [ 'table' => 'X' ] ],
170 ],
171 // No-op by default
172 "SELECT field FROM table"
173 ],
174 [
175 [
176 'tables' => 'table',
177 'fields' => [ 'field' ],
178 'options' => [ 'DISTINCT', 'LOCK IN SHARE MODE' ],
179 ],
180 "SELECT DISTINCT field FROM table LOCK IN SHARE MODE"
181 ],
182 [
183 [
184 'tables' => 'table',
185 'fields' => [ 'field' ],
186 'options' => [ 'EXPLAIN' => true ],
187 ],
188 'EXPLAIN SELECT field FROM table'
189 ],
190 [
191 [
192 'tables' => 'table',
193 'fields' => [ 'field' ],
194 'options' => [ 'FOR UPDATE' ],
195 ],
196 "SELECT field FROM table FOR UPDATE"
197 ],
198 ];
199 }
200
207 public function testUpdate( $sql, $sqlText ) {
208 $this->database->update(
209 $sql['table'],
210 $sql['values'],
211 $sql['conds'],
212 __METHOD__,
213 isset( $sql['options'] ) ? $sql['options'] : []
214 );
215 $this->assertLastSql( $sqlText );
216 }
217
218 public static function provideUpdate() {
219 return [
220 [
221 [
222 'table' => 'table',
223 'values' => [ 'field' => 'text', 'field2' => 'text2' ],
224 'conds' => [ 'alias' => 'text' ],
225 ],
226 "UPDATE table " .
227 "SET field = 'text'" .
228 ",field2 = 'text2' " .
229 "WHERE alias = 'text'"
230 ],
231 [
232 [
233 'table' => 'table',
234 'values' => [ 'field = other', 'field2' => 'text2' ],
235 'conds' => [ 'id' => '1' ],
236 ],
237 "UPDATE table " .
238 "SET field = other" .
239 ",field2 = 'text2' " .
240 "WHERE id = '1'"
241 ],
242 [
243 [
244 'table' => 'table',
245 'values' => [ 'field = other', 'field2' => 'text2' ],
246 'conds' => '*',
247 ],
248 "UPDATE table " .
249 "SET field = other" .
250 ",field2 = 'text2'"
251 ],
252 ];
253 }
254
259 public function testDelete( $sql, $sqlText ) {
260 $this->database->delete(
261 $sql['table'],
262 $sql['conds'],
263 __METHOD__
264 );
265 $this->assertLastSql( $sqlText );
266 }
267
268 public static function provideDelete() {
269 return [
270 [
271 [
272 'table' => 'table',
273 'conds' => [ 'alias' => 'text' ],
274 ],
275 "DELETE FROM table " .
276 "WHERE alias = 'text'"
277 ],
278 [
279 [
280 'table' => 'table',
281 'conds' => '*',
282 ],
283 "DELETE FROM table"
284 ],
285 ];
286 }
287
292 public function testUpsert( $sql, $sqlText ) {
293 $this->database->upsert(
294 $sql['table'],
295 $sql['rows'],
296 $sql['uniqueIndexes'],
297 $sql['set'],
298 __METHOD__
299 );
300 $this->assertLastSql( $sqlText );
301 }
302
303 public static function provideUpsert() {
304 return [
305 [
306 [
307 'table' => 'upsert_table',
308 'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
309 'uniqueIndexes' => [ 'field' ],
310 'set' => [ 'field' => 'set' ],
311 ],
312 "BEGIN; " .
313 "UPDATE upsert_table " .
314 "SET field = 'set' " .
315 "WHERE ((field = 'text')); " .
316 "INSERT IGNORE INTO upsert_table " .
317 "(field,field2) " .
318 "VALUES ('text','text2'); " .
319 "COMMIT"
320 ],
321 ];
322 }
323
328 public function testDeleteJoin( $sql, $sqlText ) {
329 $this->database->deleteJoin(
330 $sql['delTable'],
331 $sql['joinTable'],
332 $sql['delVar'],
333 $sql['joinVar'],
334 $sql['conds'],
335 __METHOD__
336 );
337 $this->assertLastSql( $sqlText );
338 }
339
340 public static function provideDeleteJoin() {
341 return [
342 [
343 [
344 'delTable' => 'table',
345 'joinTable' => 'table_join',
346 'delVar' => 'field',
347 'joinVar' => 'field_join',
348 'conds' => [ 'alias' => 'text' ],
349 ],
350 "DELETE FROM table " .
351 "WHERE field IN (" .
352 "SELECT field_join FROM table_join WHERE alias = 'text'" .
353 ")"
354 ],
355 [
356 [
357 'delTable' => 'table',
358 'joinTable' => 'table_join',
359 'delVar' => 'field',
360 'joinVar' => 'field_join',
361 'conds' => '*',
362 ],
363 "DELETE FROM table " .
364 "WHERE field IN (" .
365 "SELECT field_join FROM table_join " .
366 ")"
367 ],
368 ];
369 }
370
376 public function testInsert( $sql, $sqlText ) {
377 $this->database->insert(
378 $sql['table'],
379 $sql['rows'],
380 __METHOD__,
381 isset( $sql['options'] ) ? $sql['options'] : []
382 );
383 $this->assertLastSql( $sqlText );
384 }
385
386 public static function provideInsert() {
387 return [
388 [
389 [
390 'table' => 'table',
391 'rows' => [ 'field' => 'text', 'field2' => 2 ],
392 ],
393 "INSERT INTO table " .
394 "(field,field2) " .
395 "VALUES ('text','2')"
396 ],
397 [
398 [
399 'table' => 'table',
400 'rows' => [ 'field' => 'text', 'field2' => 2 ],
401 'options' => 'IGNORE',
402 ],
403 "INSERT IGNORE INTO table " .
404 "(field,field2) " .
405 "VALUES ('text','2')"
406 ],
407 [
408 [
409 'table' => 'table',
410 'rows' => [
411 [ 'field' => 'text', 'field2' => 2 ],
412 [ 'field' => 'multi', 'field2' => 3 ],
413 ],
414 'options' => 'IGNORE',
415 ],
416 "INSERT IGNORE INTO table " .
417 "(field,field2) " .
418 "VALUES " .
419 "('text','2')," .
420 "('multi','3')"
421 ],
422 ];
423 }
424
430 public function testInsertSelect( $sql, $sqlTextNative, $sqlSelect, $sqlInsert ) {
431 $this->database->insertSelect(
432 $sql['destTable'],
433 $sql['srcTable'],
434 $sql['varMap'],
435 $sql['conds'],
436 __METHOD__,
437 isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : [],
438 isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : [],
439 isset( $sql['selectJoinConds'] ) ? $sql['selectJoinConds'] : []
440 );
441 $this->assertLastSql( $sqlTextNative );
442
443 $dbWeb = new DatabaseTestHelper( __CLASS__, [ 'cliMode' => false ] );
444 $dbWeb->forceNextResult( [
445 array_flip( array_keys( $sql['varMap'] ) )
446 ] );
447 $dbWeb->insertSelect(
448 $sql['destTable'],
449 $sql['srcTable'],
450 $sql['varMap'],
451 $sql['conds'],
452 __METHOD__,
453 isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : [],
454 isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : [],
455 isset( $sql['selectJoinConds'] ) ? $sql['selectJoinConds'] : []
456 );
457 $this->assertLastSqlDb( implode( '; ', [ $sqlSelect, $sqlInsert ] ), $dbWeb );
458 }
459
460 public static function provideInsertSelect() {
461 return [
462 [
463 [
464 'destTable' => 'insert_table',
465 'srcTable' => 'select_table',
466 'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
467 'conds' => '*',
468 ],
469 "INSERT INTO insert_table " .
470 "(field_insert,field) " .
471 "SELECT field_select,field2 " .
472 "FROM select_table WHERE *",
473 "SELECT field_select AS field_insert,field2 AS field " .
474 "FROM select_table WHERE * FOR UPDATE",
475 "INSERT INTO insert_table (field_insert,field) VALUES ('0','1')"
476 ],
477 [
478 [
479 'destTable' => 'insert_table',
480 'srcTable' => 'select_table',
481 'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
482 'conds' => [ 'field' => 2 ],
483 ],
484 "INSERT INTO insert_table " .
485 "(field_insert,field) " .
486 "SELECT field_select,field2 " .
487 "FROM select_table " .
488 "WHERE field = '2'",
489 "SELECT field_select AS field_insert,field2 AS field FROM " .
490 "select_table WHERE field = '2' FOR UPDATE",
491 "INSERT INTO insert_table (field_insert,field) VALUES ('0','1')"
492 ],
493 [
494 [
495 'destTable' => 'insert_table',
496 'srcTable' => 'select_table',
497 'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
498 'conds' => [ 'field' => 2 ],
499 'insertOptions' => 'IGNORE',
500 'selectOptions' => [ 'ORDER BY' => 'field' ],
501 ],
502 "INSERT IGNORE INTO insert_table " .
503 "(field_insert,field) " .
504 "SELECT field_select,field2 " .
505 "FROM select_table " .
506 "WHERE field = '2' " .
507 "ORDER BY field",
508 "SELECT field_select AS field_insert,field2 AS field " .
509 "FROM select_table WHERE field = '2' ORDER BY field FOR UPDATE",
510 "INSERT IGNORE INTO insert_table (field_insert,field) VALUES ('0','1')"
511 ],
512 [
513 [
514 'destTable' => 'insert_table',
515 'srcTable' => [ 'select_table1', 'select_table2' ],
516 'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
517 'conds' => [ 'field' => 2 ],
518 'selectOptions' => [ 'ORDER BY' => 'field', 'FORCE INDEX' => [ 'select_table1' => 'index1' ] ],
519 'selectJoinConds' => [
520 'select_table2' => [ 'LEFT JOIN', [ 'select_table1.foo = select_table2.bar' ] ],
521 ],
522 ],
523 "INSERT INTO insert_table " .
524 "(field_insert,field) " .
525 "SELECT field_select,field2 " .
526 "FROM select_table1 LEFT JOIN select_table2 ON ((select_table1.foo = select_table2.bar)) " .
527 "WHERE field = '2' " .
528 "ORDER BY field",
529 "SELECT field_select AS field_insert,field2 AS field " .
530 "FROM select_table1 LEFT JOIN select_table2 ON ((select_table1.foo = select_table2.bar)) " .
531 "WHERE field = '2' ORDER BY field FOR UPDATE",
532 "INSERT INTO insert_table (field_insert,field) VALUES ('0','1')"
533 ],
534 ];
535 }
536
541 public function testReplace( $sql, $sqlText ) {
542 $this->database->replace(
543 $sql['table'],
544 $sql['uniqueIndexes'],
545 $sql['rows'],
546 __METHOD__
547 );
548 $this->assertLastSql( $sqlText );
549 }
550
551 public static function provideReplace() {
552 return [
553 [
554 [
555 'table' => 'replace_table',
556 'uniqueIndexes' => [ 'field' ],
557 'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
558 ],
559 "DELETE FROM replace_table " .
560 "WHERE ( field='text' ); " .
561 "INSERT INTO replace_table " .
562 "(field,field2) " .
563 "VALUES ('text','text2')"
564 ],
565 [
566 [
567 'table' => 'module_deps',
568 'uniqueIndexes' => [ [ 'md_module', 'md_skin' ] ],
569 'rows' => [
570 'md_module' => 'module',
571 'md_skin' => 'skin',
572 'md_deps' => 'deps',
573 ],
574 ],
575 "DELETE FROM module_deps " .
576 "WHERE ( md_module='module' AND md_skin='skin' ); " .
577 "INSERT INTO module_deps " .
578 "(md_module,md_skin,md_deps) " .
579 "VALUES ('module','skin','deps')"
580 ],
581 [
582 [
583 'table' => 'module_deps',
584 'uniqueIndexes' => [ [ 'md_module', 'md_skin' ] ],
585 'rows' => [
586 [
587 'md_module' => 'module',
588 'md_skin' => 'skin',
589 'md_deps' => 'deps',
590 ], [
591 'md_module' => 'module2',
592 'md_skin' => 'skin2',
593 'md_deps' => 'deps2',
594 ],
595 ],
596 ],
597 "DELETE FROM module_deps " .
598 "WHERE ( md_module='module' AND md_skin='skin' ); " .
599 "INSERT INTO module_deps " .
600 "(md_module,md_skin,md_deps) " .
601 "VALUES ('module','skin','deps'); " .
602 "DELETE FROM module_deps " .
603 "WHERE ( md_module='module2' AND md_skin='skin2' ); " .
604 "INSERT INTO module_deps " .
605 "(md_module,md_skin,md_deps) " .
606 "VALUES ('module2','skin2','deps2')"
607 ],
608 [
609 [
610 'table' => 'module_deps',
611 'uniqueIndexes' => [ 'md_module', 'md_skin' ],
612 'rows' => [
613 [
614 'md_module' => 'module',
615 'md_skin' => 'skin',
616 'md_deps' => 'deps',
617 ], [
618 'md_module' => 'module2',
619 'md_skin' => 'skin2',
620 'md_deps' => 'deps2',
621 ],
622 ],
623 ],
624 "DELETE FROM module_deps " .
625 "WHERE ( md_module='module' ) OR ( md_skin='skin' ); " .
626 "INSERT INTO module_deps " .
627 "(md_module,md_skin,md_deps) " .
628 "VALUES ('module','skin','deps'); " .
629 "DELETE FROM module_deps " .
630 "WHERE ( md_module='module2' ) OR ( md_skin='skin2' ); " .
631 "INSERT INTO module_deps " .
632 "(md_module,md_skin,md_deps) " .
633 "VALUES ('module2','skin2','deps2')"
634 ],
635 [
636 [
637 'table' => 'module_deps',
638 'uniqueIndexes' => [],
639 'rows' => [
640 'md_module' => 'module',
641 'md_skin' => 'skin',
642 'md_deps' => 'deps',
643 ],
644 ],
645 "INSERT INTO module_deps " .
646 "(md_module,md_skin,md_deps) " .
647 "VALUES ('module','skin','deps')"
648 ],
649 ];
650 }
651
656 public function testNativeReplace( $sql, $sqlText ) {
657 $this->database->nativeReplace(
658 $sql['table'],
659 $sql['rows'],
660 __METHOD__
661 );
662 $this->assertLastSql( $sqlText );
663 }
664
665 public static function provideNativeReplace() {
666 return [
667 [
668 [
669 'table' => 'replace_table',
670 'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
671 ],
672 "REPLACE INTO replace_table " .
673 "(field,field2) " .
674 "VALUES ('text','text2')"
675 ],
676 ];
677 }
678
683 public function testConditional( $sql, $sqlText ) {
684 $this->assertEquals( trim( $this->database->conditional(
685 $sql['conds'],
686 $sql['true'],
687 $sql['false']
688 ) ), $sqlText );
689 }
690
691 public static function provideConditional() {
692 return [
693 [
694 [
695 'conds' => [ 'field' => 'text' ],
696 'true' => 1,
697 'false' => 'NULL',
698 ],
699 "(CASE WHEN field = 'text' THEN 1 ELSE NULL END)"
700 ],
701 [
702 [
703 'conds' => [ 'field' => 'text', 'field2' => 'anothertext' ],
704 'true' => 1,
705 'false' => 'NULL',
706 ],
707 "(CASE WHEN field = 'text' AND field2 = 'anothertext' THEN 1 ELSE NULL END)"
708 ],
709 [
710 [
711 'conds' => 'field=1',
712 'true' => 1,
713 'false' => 'NULL',
714 ],
715 "(CASE WHEN field=1 THEN 1 ELSE NULL END)"
716 ],
717 ];
718 }
719
724 public function testBuildConcat( $stringList, $sqlText ) {
725 $this->assertEquals( trim( $this->database->buildConcat(
726 $stringList
727 ) ), $sqlText );
728 }
729
730 public static function provideBuildConcat() {
731 return [
732 [
733 [ 'field', 'field2' ],
734 "CONCAT(field,field2)"
735 ],
736 [
737 [ "'test'", 'field2' ],
738 "CONCAT('test',field2)"
739 ],
740 ];
741 }
742
748 public function testBuildLike( $array, $sqlText ) {
749 $this->assertEquals( trim( $this->database->buildLike(
750 $array
751 ) ), $sqlText );
752 }
753
754 public static function provideBuildLike() {
755 return [
756 [
757 'text',
758 "LIKE 'text' ESCAPE '`'"
759 ],
760 [
761 [ 'text', new LikeMatch( '%' ) ],
762 "LIKE 'text%' ESCAPE '`'"
763 ],
764 [
765 [ 'text', new LikeMatch( '%' ), 'text2' ],
766 "LIKE 'text%text2' ESCAPE '`'"
767 ],
768 [
769 [ 'text', new LikeMatch( '_' ) ],
770 "LIKE 'text_' ESCAPE '`'"
771 ],
772 [
773 'more_text',
774 "LIKE 'more`_text' ESCAPE '`'"
775 ],
776 [
777 [ 'C:\\Windows\\', new LikeMatch( '%' ) ],
778 "LIKE 'C:\\Windows\\%' ESCAPE '`'"
779 ],
780 [
781 [ 'accent`_test`', new LikeMatch( '%' ) ],
782 "LIKE 'accent```_test``%' ESCAPE '`'"
783 ],
784 ];
785 }
786
791 public function testUnionQueries( $sql, $sqlText ) {
792 $this->assertEquals( trim( $this->database->unionQueries(
793 $sql['sqls'],
794 $sql['all']
795 ) ), $sqlText );
796 }
797
798 public static function provideUnionQueries() {
799 return [
800 [
801 [
802 'sqls' => [ 'RAW SQL', 'RAW2SQL' ],
803 'all' => true,
804 ],
805 "(RAW SQL) UNION ALL (RAW2SQL)"
806 ],
807 [
808 [
809 'sqls' => [ 'RAW SQL', 'RAW2SQL' ],
810 'all' => false,
811 ],
812 "(RAW SQL) UNION (RAW2SQL)"
813 ],
814 [
815 [
816 'sqls' => [ 'RAW SQL', 'RAW2SQL', 'RAW3SQL' ],
817 'all' => false,
818 ],
819 "(RAW SQL) UNION (RAW2SQL) UNION (RAW3SQL)"
820 ],
821 ];
822 }
823
828 public function testUnionConditionPermutations( $params, $expect ) {
829 if ( isset( $params['unionSupportsOrderAndLimit'] ) ) {
830 $this->database->setUnionSupportsOrderAndLimit( $params['unionSupportsOrderAndLimit'] );
831 }
832
833 $sql = trim( $this->database->unionConditionPermutations(
834 $params['table'],
835 $params['vars'],
836 $params['permute_conds'],
837 isset( $params['extra_conds'] ) ? $params['extra_conds'] : '',
838 'FNAME',
839 isset( $params['options'] ) ? $params['options'] : [],
840 isset( $params['join_conds'] ) ? $params['join_conds'] : []
841 ) );
842 $this->assertEquals( $expect, $sql );
843 }
844
845 public static function provideUnionConditionPermutations() {
846 return [
847 // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
848 [
849 [
850 'table' => [ 'table1', 'table2' ],
851 'vars' => [ 'field1', 'alias' => 'field2' ],
852 'permute_conds' => [
853 'field3' => [ 1, 2, 3 ],
854 'duplicates' => [ 4, 5, 4 ],
855 'empty' => [],
856 'single' => [ 0 ],
857 ],
858 'extra_conds' => 'table2.bar > 23',
859 'options' => [
860 'ORDER BY' => [ 'field1', 'alias' ],
861 'INNER ORDER BY' => [ 'field1', 'field2' ],
862 'LIMIT' => 100,
863 ],
864 'join_conds' => [
865 'table2' => [ 'JOIN', 'table1.foo_id = table2.foo_id' ],
866 ],
867 ],
868 "(SELECT field1,field2 AS alias FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id)) WHERE field3 = '1' AND duplicates = '4' AND single = '0' AND (table2.bar > 23) ORDER BY field1,field2 LIMIT 100 ) UNION ALL " .
869 "(SELECT field1,field2 AS alias FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id)) WHERE field3 = '1' AND duplicates = '5' AND single = '0' AND (table2.bar > 23) ORDER BY field1,field2 LIMIT 100 ) UNION ALL " .
870 "(SELECT field1,field2 AS alias FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id)) WHERE field3 = '2' AND duplicates = '4' AND single = '0' AND (table2.bar > 23) ORDER BY field1,field2 LIMIT 100 ) UNION ALL " .
871 "(SELECT field1,field2 AS alias FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id)) WHERE field3 = '2' AND duplicates = '5' AND single = '0' AND (table2.bar > 23) ORDER BY field1,field2 LIMIT 100 ) UNION ALL " .
872 "(SELECT field1,field2 AS alias FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id)) WHERE field3 = '3' AND duplicates = '4' AND single = '0' AND (table2.bar > 23) ORDER BY field1,field2 LIMIT 100 ) UNION ALL " .
873 "(SELECT field1,field2 AS alias FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id)) WHERE field3 = '3' AND duplicates = '5' AND single = '0' AND (table2.bar > 23) ORDER BY field1,field2 LIMIT 100 ) " .
874 "ORDER BY field1,alias LIMIT 100"
875 ],
876 [
877 [
878 'table' => 'foo',
879 'vars' => [ 'foo_id' ],
880 'permute_conds' => [
881 'bar' => [ 1, 2, 3 ],
882 ],
883 'extra_conds' => [ 'baz' => null ],
884 'options' => [
885 'NOTALL',
886 'ORDER BY' => [ 'foo_id' ],
887 'LIMIT' => 25,
888 ],
889 ],
890 "(SELECT foo_id FROM foo WHERE bar = '1' AND baz IS NULL ORDER BY foo_id LIMIT 25 ) UNION " .
891 "(SELECT foo_id FROM foo WHERE bar = '2' AND baz IS NULL ORDER BY foo_id LIMIT 25 ) UNION " .
892 "(SELECT foo_id FROM foo WHERE bar = '3' AND baz IS NULL ORDER BY foo_id LIMIT 25 ) " .
893 "ORDER BY foo_id LIMIT 25"
894 ],
895 [
896 [
897 'table' => 'foo',
898 'vars' => [ 'foo_id' ],
899 'permute_conds' => [
900 'bar' => [ 1, 2, 3 ],
901 ],
902 'extra_conds' => [ 'baz' => null ],
903 'options' => [
904 'NOTALL' => true,
905 'ORDER BY' => [ 'foo_id' ],
906 'LIMIT' => 25,
907 ],
908 'unionSupportsOrderAndLimit' => false,
909 ],
910 "(SELECT foo_id FROM foo WHERE bar = '1' AND baz IS NULL ) UNION " .
911 "(SELECT foo_id FROM foo WHERE bar = '2' AND baz IS NULL ) UNION " .
912 "(SELECT foo_id FROM foo WHERE bar = '3' AND baz IS NULL ) " .
913 "ORDER BY foo_id LIMIT 25"
914 ],
915 [
916 [
917 'table' => 'foo',
918 'vars' => [ 'foo_id' ],
919 'permute_conds' => [],
920 'extra_conds' => [ 'baz' => null ],
921 'options' => [
922 'ORDER BY' => [ 'foo_id' ],
923 'LIMIT' => 25,
924 ],
925 ],
926 "SELECT foo_id FROM foo WHERE baz IS NULL ORDER BY foo_id LIMIT 25"
927 ],
928 [
929 [
930 'table' => 'foo',
931 'vars' => [ 'foo_id' ],
932 'permute_conds' => [
933 'bar' => [],
934 ],
935 'extra_conds' => [ 'baz' => null ],
936 'options' => [
937 'ORDER BY' => [ 'foo_id' ],
938 'LIMIT' => 25,
939 ],
940 ],
941 "SELECT foo_id FROM foo WHERE baz IS NULL ORDER BY foo_id LIMIT 25"
942 ],
943 [
944 [
945 'table' => 'foo',
946 'vars' => [ 'foo_id' ],
947 'permute_conds' => [
948 'bar' => [ 1 ],
949 ],
950 'options' => [
951 'ORDER BY' => [ 'foo_id' ],
952 'LIMIT' => 25,
953 'OFFSET' => 150,
954 ],
955 ],
956 "SELECT foo_id FROM foo WHERE bar = '1' ORDER BY foo_id LIMIT 150,25"
957 ],
958 [
959 [
960 'table' => 'foo',
961 'vars' => [ 'foo_id' ],
962 'permute_conds' => [],
963 'extra_conds' => [ 'baz' => null ],
964 'options' => [
965 'ORDER BY' => [ 'foo_id' ],
966 'LIMIT' => 25,
967 'OFFSET' => 150,
968 'INNER ORDER BY' => [ 'bar_id' ],
969 ],
970 ],
971 "(SELECT foo_id FROM foo WHERE baz IS NULL ORDER BY bar_id LIMIT 175 ) ORDER BY foo_id LIMIT 150,25"
972 ],
973 [
974 [
975 'table' => 'foo',
976 'vars' => [ 'foo_id' ],
977 'permute_conds' => [],
978 'extra_conds' => [ 'baz' => null ],
979 'options' => [
980 'ORDER BY' => [ 'foo_id' ],
981 'LIMIT' => 25,
982 'OFFSET' => 150,
983 'INNER ORDER BY' => [ 'bar_id' ],
984 ],
985 'unionSupportsOrderAndLimit' => false,
986 ],
987 "SELECT foo_id FROM foo WHERE baz IS NULL ORDER BY foo_id LIMIT 150,25"
988 ],
989 // @codingStandardsIgnoreEnd
990 ];
991 }
992
997 public function testTransactionCommit() {
998 $this->database->begin( __METHOD__ );
999 $this->database->commit( __METHOD__ );
1000 $this->assertLastSql( 'BEGIN; COMMIT' );
1001 }
1002
1007 public function testTransactionRollback() {
1008 $this->database->begin( __METHOD__ );
1009 $this->database->rollback( __METHOD__ );
1010 $this->assertLastSql( 'BEGIN; ROLLBACK' );
1011 }
1012
1016 public function testDropTable() {
1017 $this->database->setExistingTables( [ 'table' ] );
1018 $this->database->dropTable( 'table', __METHOD__ );
1019 $this->assertLastSql( 'DROP TABLE table CASCADE' );
1020 }
1021
1025 public function testDropNonExistingTable() {
1026 $this->assertFalse(
1027 $this->database->dropTable( 'non_existing', __METHOD__ )
1028 );
1029 }
1030
1035 public function testMakeList( $list, $mode, $sqlText ) {
1036 $this->assertEquals( trim( $this->database->makeList(
1037 $list, $mode
1038 ) ), $sqlText );
1039 }
1040
1041 public static function provideMakeList() {
1042 return [
1043 [
1044 [ 'value', 'value2' ],
1045 LIST_COMMA,
1046 "'value','value2'"
1047 ],
1048 [
1049 [ 'field', 'field2' ],
1050 LIST_NAMES,
1051 "field,field2"
1052 ],
1053 [
1054 [ 'field' => 'value', 'field2' => 'value2' ],
1055 LIST_AND,
1056 "field = 'value' AND field2 = 'value2'"
1057 ],
1058 [
1059 [ 'field' => null, "field2 != 'value2'" ],
1060 LIST_AND,
1061 "field IS NULL AND (field2 != 'value2')"
1062 ],
1063 [
1064 [ 'field' => [ 'value', null, 'value2' ], 'field2' => 'value2' ],
1065 LIST_AND,
1066 "(field IN ('value','value2') OR field IS NULL) AND field2 = 'value2'"
1067 ],
1068 [
1069 [ 'field' => [ null ], 'field2' => null ],
1070 LIST_AND,
1071 "field IS NULL AND field2 IS NULL"
1072 ],
1073 [
1074 [ 'field' => 'value', 'field2' => 'value2' ],
1075 LIST_OR,
1076 "field = 'value' OR field2 = 'value2'"
1077 ],
1078 [
1079 [ 'field' => 'value', 'field2' => null ],
1080 LIST_OR,
1081 "field = 'value' OR field2 IS NULL"
1082 ],
1083 [
1084 [ 'field' => [ 'value', 'value2' ], 'field2' => [ 'value' ] ],
1085 LIST_OR,
1086 "field IN ('value','value2') OR field2 = 'value'"
1087 ],
1088 [
1089 [ 'field' => [ null, 'value', null, 'value2' ], "field2 != 'value2'" ],
1090 LIST_OR,
1091 "(field IN ('value','value2') OR field IS NULL) OR (field2 != 'value2')"
1092 ],
1093 [
1094 [ 'field' => 'value', 'field2' => 'value2' ],
1095 LIST_SET,
1096 "field = 'value',field2 = 'value2'"
1097 ],
1098 [
1099 [ 'field' => 'value', 'field2' => null ],
1100 LIST_SET,
1101 "field = 'value',field2 = NULL"
1102 ],
1103 [
1104 [ 'field' => 'value', "field2 != 'value2'" ],
1105 LIST_SET,
1106 "field = 'value',field2 != 'value2'"
1107 ],
1108 ];
1109 }
1110
1114 public function testSessionTempTables() {
1115 $temp1 = $this->database->tableName( 'tmp_table_1' );
1116 $temp2 = $this->database->tableName( 'tmp_table_2' );
1117 $temp3 = $this->database->tableName( 'tmp_table_3' );
1118
1119 $this->database->query( "CREATE TEMPORARY TABLE $temp1 LIKE orig_tbl", __METHOD__ );
1120 $this->database->query( "CREATE TEMPORARY TABLE $temp2 LIKE orig_tbl", __METHOD__ );
1121 $this->database->query( "CREATE TEMPORARY TABLE $temp3 LIKE orig_tbl", __METHOD__ );
1122
1123 $this->assertTrue( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
1124 $this->assertTrue( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
1125 $this->assertTrue( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
1126
1127 $this->database->dropTable( 'tmp_table_1', __METHOD__ );
1128 $this->database->dropTable( 'tmp_table_2', __METHOD__ );
1129 $this->database->dropTable( 'tmp_table_3', __METHOD__ );
1130
1131 $this->assertFalse( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
1132 $this->assertFalse( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
1133 $this->assertFalse( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
1134
1135 $this->database->query( "CREATE TEMPORARY TABLE tmp_table_1 LIKE orig_tbl", __METHOD__ );
1136 $this->database->query( "CREATE TEMPORARY TABLE 'tmp_table_2' LIKE orig_tbl", __METHOD__ );
1137 $this->database->query( "CREATE TEMPORARY TABLE `tmp_table_3` LIKE orig_tbl", __METHOD__ );
1138
1139 $this->assertTrue( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
1140 $this->assertTrue( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
1141 $this->assertTrue( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
1142
1143 $this->database->query( "DROP TEMPORARY TABLE tmp_table_1 LIKE orig_tbl", __METHOD__ );
1144 $this->database->query( "DROP TEMPORARY TABLE 'tmp_table_2' LIKE orig_tbl", __METHOD__ );
1145 $this->database->query( "DROP TABLE `tmp_table_3` LIKE orig_tbl", __METHOD__ );
1146
1147 $this->assertFalse( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
1148 $this->assertFalse( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
1149 $this->assertFalse( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
1150 }
1151}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
Test the parts of the Database abstract class that deal with creating SQL text.
static provideUnionConditionPermutations()
static provideNativeReplace()
testSessionTempTables()
Wikimedia\Rdbms\Database::registerTempTableOperation.
testSelect( $sql, $sqlText)
provideSelect Wikimedia\Rdbms\Database::select Wikimedia\Rdbms\Database::selectSQLText Wikimedia\Rdbm...
testBuildConcat( $stringList, $sqlText)
provideBuildConcat Wikimedia\Rdbms\Database::buildConcat
testDropTable()
Wikimedia\Rdbms\Database::dropTable.
testMakeList( $list, $mode, $sqlText)
provideMakeList Wikimedia\Rdbms\Database::makeList
static provideConditional()
testBuildLike( $array, $sqlText)
provideBuildLike Wikimedia\Rdbms\Database::buildLike Wikimedia\Rdbms\Database::escapeLikeInternal
static provideUnionQueries()
testConditional( $sql, $sqlText)
provideConditional Wikimedia\Rdbms\Database::conditional
testTransactionRollback()
Wikimedia\Rdbms\Database::rollback Wikimedia\Rdbms\Database::doRollback.
static provideInsertSelect()
static provideBuildConcat()
testReplace( $sql, $sqlText)
provideReplace Wikimedia\Rdbms\Database::replace
testUnionQueries( $sql, $sqlText)
provideUnionQueries Wikimedia\Rdbms\Database::unionQueries
testUnionConditionPermutations( $params, $expect)
provideUnionConditionPermutations Wikimedia\Rdbms\Database::unionConditionPermutations
testUpsert( $sql, $sqlText)
provideUpsert Wikimedia\Rdbms\Database::upsert
testDropNonExistingTable()
Wikimedia\Rdbms\Database::dropTable.
testUpdate( $sql, $sqlText)
provideUpdate Wikimedia\Rdbms\Database::update Wikimedia\Rdbms\Database::makeUpdateOptions Wikimedia\...
testInsert( $sql, $sqlText)
provideInsert Wikimedia\Rdbms\Database::insert Wikimedia\Rdbms\Database::makeInsertOptions
testDelete( $sql, $sqlText)
provideDelete Wikimedia\Rdbms\Database::delete
testNativeReplace( $sql, $sqlText)
provideNativeReplace Wikimedia\Rdbms\Database::nativeReplace
assertLastSql( $sqlText)
testTransactionCommit()
Wikimedia\Rdbms\Database::commit Wikimedia\Rdbms\Database::doCommit.
DatabaseTestHelper $database
assertLastSqlDb( $sqlText, DatabaseTestHelper $db)
testInsertSelect( $sql, $sqlTextNative, $sqlSelect, $sqlInsert)
provideInsertSelect Wikimedia\Rdbms\Database::insertSelect Wikimedia\Rdbms\Database::nativeInsertSele...
testDeleteJoin( $sql, $sqlText)
provideDeleteJoin Wikimedia\Rdbms\Database::deleteJoin
Helper for testing the methods from the Database class.
getLastSqls()
Returns SQL queries grouped by '; ' Clear the list of queries that have been done so far.
Used by Database::buildLike() to represent characters that have special meaning in SQL LIKE clauses a...
Definition LikeMatch.php:10
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the database
Definition design.txt:13
const LIST_NAMES
Definition Defines.php:46
const LIST_COMMA
Definition Defines.php:43
const LIST_SET
Definition Defines.php:45
const LIST_OR
Definition Defines.php:47
const LIST_AND
Definition Defines.php:44
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition hooks.txt:1976
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition injection.txt:37
$params