3 use Wikimedia\Rdbms\Database
;
4 use Wikimedia\Rdbms\IDatabase
;
5 use Wikimedia\Rdbms\DatabasePostgres
;
6 use Wikimedia\ScopedCallback
;
7 use Wikimedia\TestingAccessWrapper
;
12 class DatabasePostgresTest
extends MediaWikiTestCase
{
14 private function doTestInsertIgnore() {
16 $reset = new ScopedCallback( function () use ( $fname ) {
17 if ( $this->db
->explicitTrxActive() ) {
18 $this->db
->rollback( $fname );
20 $this->db
->query( 'DROP TABLE IF EXISTS ' . $this->db
->tableName( 'foo' ), $fname );
24 "CREATE TEMPORARY TABLE {$this->db->tableName( 'foo' )} (i INTEGER NOT NULL PRIMARY KEY)",
27 $this->db
->insert( 'foo', [ [ 'i' => 1 ], [ 'i' => 2 ] ], __METHOD__
);
29 // Normal INSERT IGNORE
30 $this->db
->begin( __METHOD__
);
32 'foo', [ [ 'i' => 3 ], [ 'i' => 2 ], [ 'i' => 5 ] ], __METHOD__
, [ 'IGNORE' ]
34 $this->assertSame( 2, $this->db
->affectedRows() );
36 [ '1', '2', '3', '5' ],
37 $this->db
->selectFieldValues( 'foo', 'i', [], __METHOD__
, [ 'ORDER BY' => 'i' ] )
39 $this->db
->rollback( __METHOD__
);
41 // INSERT IGNORE doesn't ignore stuff like NOT NULL violations
42 $this->db
->begin( __METHOD__
);
43 $this->db
->startAtomic( __METHOD__
, IDatabase
::ATOMIC_CANCELABLE
);
46 'foo', [ [ 'i' => 7 ], [ 'i' => null ] ], __METHOD__
, [ 'IGNORE' ]
48 $this->db
->endAtomic( __METHOD__
);
49 $this->fail( 'Expected exception not thrown' );
50 } catch ( DBQueryError
$e ) {
51 $this->assertSame( 0, $this->db
->affectedRows() );
52 $this->db
->cancelAtomic( __METHOD__
);
56 $this->db
->selectFieldValues( 'foo', 'i', [], __METHOD__
, [ 'ORDER BY' => 'i' ] )
58 $this->db
->rollback( __METHOD__
);
62 * @covers Wikimedia\Rdbms\DatabasePostgres::insert
64 public function testInsertIgnoreOld() {
65 if ( !$this->db
instanceof DatabasePostgres
) {
66 $this->markTestSkipped( 'Not PostgreSQL' );
68 if ( $this->db
->getServerVersion() < 9.5 ) {
69 $this->doTestInsertIgnore();
71 // Hack version to make it take the old code path
72 $w = TestingAccessWrapper
::newFromObject( $this->db
);
73 $oldVer = $w->numericVersion
;
74 $w->numericVersion
= 9.4;
76 $this->doTestInsertIgnore();
78 $w->numericVersion
= $oldVer;
84 * @covers Wikimedia\Rdbms\DatabasePostgres::insert
86 public function testInsertIgnoreNew() {
87 if ( !$this->db
instanceof DatabasePostgres
) {
88 $this->markTestSkipped( 'Not PostgreSQL' );
90 if ( $this->db
->getServerVersion() < 9.5 ) {
91 $this->markTestSkipped( 'PostgreSQL version is ' . $this->db
->getServerVersion() );
94 $this->doTestInsertIgnore();
97 private function doTestInsertSelectIgnore() {
99 $reset = new ScopedCallback( function () use ( $fname ) {
100 if ( $this->db
->explicitTrxActive() ) {
101 $this->db
->rollback( $fname );
103 $this->db
->query( 'DROP TABLE IF EXISTS ' . $this->db
->tableName( 'foo' ), $fname );
104 $this->db
->query( 'DROP TABLE IF EXISTS ' . $this->db
->tableName( 'bar' ), $fname );
108 "CREATE TEMPORARY TABLE {$this->db->tableName( 'foo' )} (i INTEGER)",
112 "CREATE TEMPORARY TABLE {$this->db->tableName( 'bar' )} (i INTEGER NOT NULL PRIMARY KEY)",
115 $this->db
->insert( 'bar', [ [ 'i' => 1 ], [ 'i' => 2 ] ], __METHOD__
);
117 // Normal INSERT IGNORE
118 $this->db
->begin( __METHOD__
);
119 $this->db
->insert( 'foo', [ [ 'i' => 3 ], [ 'i' => 2 ], [ 'i' => 5 ] ], __METHOD__
);
120 $this->db
->insertSelect( 'bar', 'foo', [ 'i' => 'i' ], [], __METHOD__
, [ 'IGNORE' ] );
121 $this->assertSame( 2, $this->db
->affectedRows() );
123 [ '1', '2', '3', '5' ],
124 $this->db
->selectFieldValues( 'bar', 'i', [], __METHOD__
, [ 'ORDER BY' => 'i' ] )
126 $this->db
->rollback( __METHOD__
);
128 // INSERT IGNORE doesn't ignore stuff like NOT NULL violations
129 $this->db
->begin( __METHOD__
);
130 $this->db
->insert( 'foo', [ [ 'i' => 7 ], [ 'i' => null ] ], __METHOD__
);
131 $this->db
->startAtomic( __METHOD__
, IDatabase
::ATOMIC_CANCELABLE
);
133 $this->db
->insertSelect( 'bar', 'foo', [ 'i' => 'i' ], [], __METHOD__
, [ 'IGNORE' ] );
134 $this->db
->endAtomic( __METHOD__
);
135 $this->fail( 'Expected exception not thrown' );
136 } catch ( DBQueryError
$e ) {
137 $this->assertSame( 0, $this->db
->affectedRows() );
138 $this->db
->cancelAtomic( __METHOD__
);
142 $this->db
->selectFieldValues( 'bar', 'i', [], __METHOD__
, [ 'ORDER BY' => 'i' ] )
144 $this->db
->rollback( __METHOD__
);
148 * @covers Wikimedia\Rdbms\DatabasePostgres::nativeInsertSelect
150 public function testInsertSelectIgnoreOld() {
151 if ( !$this->db
instanceof DatabasePostgres
) {
152 $this->markTestSkipped( 'Not PostgreSQL' );
154 if ( $this->db
->getServerVersion() < 9.5 ) {
155 $this->doTestInsertSelectIgnore();
157 // Hack version to make it take the old code path
158 $w = TestingAccessWrapper
::newFromObject( $this->db
);
159 $oldVer = $w->numericVersion
;
160 $w->numericVersion
= 9.4;
162 $this->doTestInsertSelectIgnore();
164 $w->numericVersion
= $oldVer;
170 * @covers Wikimedia\Rdbms\DatabasePostgres::nativeInsertSelect
172 public function testInsertSelectIgnoreNew() {
173 if ( !$this->db
instanceof DatabasePostgres
) {
174 $this->markTestSkipped( 'Not PostgreSQL' );
176 if ( $this->db
->getServerVersion() < 9.5 ) {
177 $this->markTestSkipped( 'PostgreSQL version is ' . $this->db
->getServerVersion() );
180 $this->doTestInsertSelectIgnore();
184 * @covers \Wikimedia\Rdbms\DatabasePostgres::getAttributes
186 public function testAttributes() {
188 Database
::attributesFromType( 'postgres' )[Database
::ATTR_SCHEMAS_AS_TABLE_GROUPS
]