Merge "Only use "*Test.php" for actual PHPUnit tests"
[lhc/web/wiklou.git] / tests / phpunit / includes / db / DatabasePostgresTest.php
1 <?php
2
3 use Wikimedia\Rdbms\IDatabase;
4 use Wikimedia\Rdbms\DatabasePostgres;
5 use Wikimedia\ScopedCallback;
6 use Wikimedia\TestingAccessWrapper;
7
8 /**
9 * @group Database
10 */
11 class DatabasePostgresTest extends MediaWikiTestCase {
12
13 private function doTestInsertIgnore() {
14 $fname = __METHOD__;
15 $reset = new ScopedCallback( function () use ( $fname ) {
16 if ( $this->db->explicitTrxActive() ) {
17 $this->db->rollback( $fname );
18 }
19 $this->db->query( 'DROP TABLE IF EXISTS ' . $this->db->tableName( 'foo' ), $fname );
20 } );
21
22 $this->db->query(
23 "CREATE TEMPORARY TABLE {$this->db->tableName( 'foo' )} (i INTEGER NOT NULL PRIMARY KEY)",
24 __METHOD__
25 );
26 $this->db->insert( 'foo', [ [ 'i' => 1 ], [ 'i' => 2 ] ], __METHOD__ );
27
28 // Normal INSERT IGNORE
29 $this->db->begin( __METHOD__ );
30 $this->db->insert(
31 'foo', [ [ 'i' => 3 ], [ 'i' => 2 ], [ 'i' => 5 ] ], __METHOD__, [ 'IGNORE' ]
32 );
33 $this->assertSame( 2, $this->db->affectedRows() );
34 $this->assertSame(
35 [ '1', '2', '3', '5' ],
36 $this->db->selectFieldValues( 'foo', 'i', [], __METHOD__, [ 'ORDER BY' => 'i' ] )
37 );
38 $this->db->rollback( __METHOD__ );
39
40 // INSERT IGNORE doesn't ignore stuff like NOT NULL violations
41 $this->db->begin( __METHOD__ );
42 $this->db->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCELABLE );
43 try {
44 $this->db->insert(
45 'foo', [ [ 'i' => 7 ], [ 'i' => null ] ], __METHOD__, [ 'IGNORE' ]
46 );
47 $this->db->endAtomic( __METHOD__ );
48 $this->fail( 'Expected exception not thrown' );
49 } catch ( DBQueryError $e ) {
50 $this->assertSame( 0, $this->db->affectedRows() );
51 $this->db->cancelAtomic( __METHOD__ );
52 }
53 $this->assertSame(
54 [ '1', '2' ],
55 $this->db->selectFieldValues( 'foo', 'i', [], __METHOD__, [ 'ORDER BY' => 'i' ] )
56 );
57 $this->db->rollback( __METHOD__ );
58 }
59
60 /**
61 * @covers Wikimedia\Rdbms\DatabasePostgres::insert
62 */
63 public function testInsertIgnoreOld() {
64 if ( !$this->db instanceof DatabasePostgres ) {
65 $this->markTestSkipped( 'Not PostgreSQL' );
66 }
67 if ( $this->db->getServerVersion() < 9.5 ) {
68 $this->doTestInsertIgnore();
69 } else {
70 // Hack version to make it take the old code path
71 $w = TestingAccessWrapper::newFromObject( $this->db );
72 $oldVer = $w->numericVersion;
73 $w->numericVersion = 9.4;
74 try {
75 $this->doTestInsertIgnore();
76 } finally {
77 $w->numericVersion = $oldVer;
78 }
79 }
80 }
81
82 /**
83 * @covers Wikimedia\Rdbms\DatabasePostgres::insert
84 */
85 public function testInsertIgnoreNew() {
86 if ( !$this->db instanceof DatabasePostgres ) {
87 $this->markTestSkipped( 'Not PostgreSQL' );
88 }
89 if ( $this->db->getServerVersion() < 9.5 ) {
90 $this->markTestSkipped( 'PostgreSQL version is ' . $this->db->getServerVersion() );
91 }
92
93 $this->doTestInsertIgnore();
94 }
95
96 private function doTestInsertSelectIgnore() {
97 $fname = __METHOD__;
98 $reset = new ScopedCallback( function () use ( $fname ) {
99 if ( $this->db->explicitTrxActive() ) {
100 $this->db->rollback( $fname );
101 }
102 $this->db->query( 'DROP TABLE IF EXISTS ' . $this->db->tableName( 'foo' ), $fname );
103 $this->db->query( 'DROP TABLE IF EXISTS ' . $this->db->tableName( 'bar' ), $fname );
104 } );
105
106 $this->db->query(
107 "CREATE TEMPORARY TABLE {$this->db->tableName( 'foo' )} (i INTEGER)",
108 __METHOD__
109 );
110 $this->db->query(
111 "CREATE TEMPORARY TABLE {$this->db->tableName( 'bar' )} (i INTEGER NOT NULL PRIMARY KEY)",
112 __METHOD__
113 );
114 $this->db->insert( 'bar', [ [ 'i' => 1 ], [ 'i' => 2 ] ], __METHOD__ );
115
116 // Normal INSERT IGNORE
117 $this->db->begin( __METHOD__ );
118 $this->db->insert( 'foo', [ [ 'i' => 3 ], [ 'i' => 2 ], [ 'i' => 5 ] ], __METHOD__ );
119 $this->db->insertSelect( 'bar', 'foo', [ 'i' => 'i' ], [], __METHOD__, [ 'IGNORE' ] );
120 $this->assertSame( 2, $this->db->affectedRows() );
121 $this->assertSame(
122 [ '1', '2', '3', '5' ],
123 $this->db->selectFieldValues( 'bar', 'i', [], __METHOD__, [ 'ORDER BY' => 'i' ] )
124 );
125 $this->db->rollback( __METHOD__ );
126
127 // INSERT IGNORE doesn't ignore stuff like NOT NULL violations
128 $this->db->begin( __METHOD__ );
129 $this->db->insert( 'foo', [ [ 'i' => 7 ], [ 'i' => null ] ], __METHOD__ );
130 $this->db->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCELABLE );
131 try {
132 $this->db->insertSelect( 'bar', 'foo', [ 'i' => 'i' ], [], __METHOD__, [ 'IGNORE' ] );
133 $this->db->endAtomic( __METHOD__ );
134 $this->fail( 'Expected exception not thrown' );
135 } catch ( DBQueryError $e ) {
136 $this->assertSame( 0, $this->db->affectedRows() );
137 $this->db->cancelAtomic( __METHOD__ );
138 }
139 $this->assertSame(
140 [ '1', '2' ],
141 $this->db->selectFieldValues( 'bar', 'i', [], __METHOD__, [ 'ORDER BY' => 'i' ] )
142 );
143 $this->db->rollback( __METHOD__ );
144 }
145
146 /**
147 * @covers Wikimedia\Rdbms\DatabasePostgres::nativeInsertSelect
148 */
149 public function testInsertSelectIgnoreOld() {
150 if ( !$this->db instanceof DatabasePostgres ) {
151 $this->markTestSkipped( 'Not PostgreSQL' );
152 }
153 if ( $this->db->getServerVersion() < 9.5 ) {
154 $this->doTestInsertSelectIgnore();
155 } else {
156 // Hack version to make it take the old code path
157 $w = TestingAccessWrapper::newFromObject( $this->db );
158 $oldVer = $w->numericVersion;
159 $w->numericVersion = 9.4;
160 try {
161 $this->doTestInsertSelectIgnore();
162 } finally {
163 $w->numericVersion = $oldVer;
164 }
165 }
166 }
167
168 /**
169 * @covers Wikimedia\Rdbms\DatabasePostgres::nativeInsertSelect
170 */
171 public function testInsertSelectIgnoreNew() {
172 if ( !$this->db instanceof DatabasePostgres ) {
173 $this->markTestSkipped( 'Not PostgreSQL' );
174 }
175 if ( $this->db->getServerVersion() < 9.5 ) {
176 $this->markTestSkipped( 'PostgreSQL version is ' . $this->db->getServerVersion() );
177 }
178
179 $this->doTestInsertSelectIgnore();
180 }
181
182 }