"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "tests/phpunit/includes/libs/rdbms/database/DatabaseSQLTest.php" between
mediawiki-1.31.1.tar.gz and mediawiki-1.32.0.tar.gz

About: MediaWiki is a wiki engine (the collaborative editing software that runs for e.g. Wikipedia, the free encyclopedia).

DatabaseSQLTest.php  (mediawiki-1.31.1):DatabaseSQLTest.php  (mediawiki-1.32.0)
skipping to change at line 49 skipping to change at line 49
/** /**
* @dataProvider provideSelect * @dataProvider provideSelect
* @covers Wikimedia\Rdbms\Database::select * @covers Wikimedia\Rdbms\Database::select
* @covers Wikimedia\Rdbms\Database::selectSQLText * @covers Wikimedia\Rdbms\Database::selectSQLText
* @covers Wikimedia\Rdbms\Database::tableNamesWithIndexClauseOrJOIN * @covers Wikimedia\Rdbms\Database::tableNamesWithIndexClauseOrJOIN
* @covers Wikimedia\Rdbms\Database::useIndexClause * @covers Wikimedia\Rdbms\Database::useIndexClause
* @covers Wikimedia\Rdbms\Database::ignoreIndexClause * @covers Wikimedia\Rdbms\Database::ignoreIndexClause
* @covers Wikimedia\Rdbms\Database::makeSelectOptions * @covers Wikimedia\Rdbms\Database::makeSelectOptions
* @covers Wikimedia\Rdbms\Database::makeOrderBy * @covers Wikimedia\Rdbms\Database::makeOrderBy
* @covers Wikimedia\Rdbms\Database::makeGroupByWithHaving * @covers Wikimedia\Rdbms\Database::makeGroupByWithHaving
* @covers Wikimedia\Rdbms\Database::selectFieldsOrOptionsAggregate
* @covers Wikimedia\Rdbms\Database::selectOptionsIncludeLocking
*/ */
public function testSelect( $sql, $sqlText ) { public function testSelect( $sql, $sqlText ) {
$this->database->select( $this->database->select(
$sql['tables'], $sql['tables'],
$sql['fields'], $sql['fields'],
isset( $sql['conds'] ) ? $sql['conds'] : [], $sql['conds'] ?? [],
__METHOD__, __METHOD__,
isset( $sql['options'] ) ? $sql['options'] : [], $sql['options'] ?? [],
isset( $sql['join_conds'] ) ? $sql['join_conds'] : [] $sql['join_conds'] ?? []
); );
$this->assertLastSql( $sqlText ); $this->assertLastSql( $sqlText );
} }
public static function provideSelect() { public static function provideSelect() {
return [ return [
[ [
[ [
'tables' => 'table', 'tables' => 'table',
'fields' => [ 'field', 'alias' => 'field2 ' ], 'fields' => [ 'field', 'alias' => 'field2 ' ],
skipping to change at line 226 skipping to change at line 228
'fields' => [ 'field' ], 'fields' => [ 'field' ],
'options' => [ 'IGNORE INDEX' => [ 'table ' => 'X' ] ], 'options' => [ 'IGNORE INDEX' => [ 'table ' => 'X' ] ],
], ],
// No-op by default // No-op by default
"SELECT field FROM table" "SELECT field FROM table"
], ],
[ [
[ [
'tables' => 'table', 'tables' => 'table',
'fields' => [ 'field' ], 'fields' => [ 'field' ],
'options' => [ 'DISTINCT', 'LOCK IN SHARE MODE' ], 'options' => [ 'DISTINCT' ],
], ],
"SELECT DISTINCT field FROM table LOCK IN SH "SELECT DISTINCT field FROM table"
ARE MODE" ],
[
[
'tables' => 'table',
'fields' => [ 'field' ],
'options' => [ 'LOCK IN SHARE MODE' ],
],
"SELECT field FROM table LOCK IN SHARE MODE"
], ],
[ [
[ [
'tables' => 'table', 'tables' => 'table',
'fields' => [ 'field' ], 'fields' => [ 'field' ],
'options' => [ 'EXPLAIN' => true ], 'options' => [ 'EXPLAIN' => true ],
], ],
'EXPLAIN SELECT field FROM table' 'EXPLAIN SELECT field FROM table'
], ],
[ [
skipping to change at line 250 skipping to change at line 260
'tables' => 'table', 'tables' => 'table',
'fields' => [ 'field' ], 'fields' => [ 'field' ],
'options' => [ 'FOR UPDATE' ], 'options' => [ 'FOR UPDATE' ],
], ],
"SELECT field FROM table FOR UPDATE" "SELECT field FROM table FOR UPDATE"
], ],
]; ];
} }
/** /**
* @dataProvider provideLockForUpdate
* @covers Wikimedia\Rdbms\Database::lockForUpdate
*/
public function testLockForUpdate( $sql, $sqlText ) {
$this->database->startAtomic( __METHOD__ );
$this->database->lockForUpdate(
$sql['tables'],
$sql['conds'] ?? [],
__METHOD__,
$sql['options'] ?? [],
$sql['join_conds'] ?? []
);
$this->database->endAtomic( __METHOD__ );
$this->assertLastSql( "BEGIN; $sqlText; COMMIT" );
}
public static function provideLockForUpdate() {
return [
[
[
'tables' => [ 'table' ],
'conds' => [ 'field' => [ 1, 2, 3, 4 ] ],
],
"SELECT COUNT(*) AS rowcount FROM " .
"(SELECT 1 FROM table WHERE field IN ('1','2','3'
,'4') " .
"FOR UPDATE) tmp_count"
],
[
[
'tables' => [ 'table', 't2' => 'table2' ]
,
'conds' => [ 'field' => 'text' ],
'options' => [ 'LIMIT' => 1, 'ORDER BY' =
> 'field' ],
'join_conds' => [ 't2' => [
'LEFT JOIN', 'tid = t2.id'
] ],
],
"SELECT COUNT(*) AS rowcount FROM " .
"(SELECT 1 FROM table LEFT JOIN table2 t2 ON ((ti
d = t2.id)) " .
"WHERE field = 'text' ORDER BY field LIMIT 1 FO
R UPDATE) tmp_count"
],
[
[
'tables' => 'table',
],
"SELECT COUNT(*) AS rowcount FROM " .
"(SELECT 1 FROM table FOR UPDATE) tmp_count"
],
];
}
/**
* @covers Wikimedia\Rdbms\Subquery * @covers Wikimedia\Rdbms\Subquery
* @dataProvider provideSelectRowCount * @dataProvider provideSelectRowCount
* @param $sql * @param $sql
* @param $sqlText * @param $sqlText
*/ */
public function testSelectRowCount( $sql, $sqlText ) { public function testSelectRowCount( $sql, $sqlText ) {
$this->database->selectRowCount( $this->database->selectRowCount(
$sql['tables'], $sql['tables'],
$sql['field'], $sql['field'],
isset( $sql['conds'] ) ? $sql['conds'] : [], $sql['conds'] ?? [],
__METHOD__, __METHOD__,
isset( $sql['options'] ) ? $sql['options'] : [], $sql['options'] ?? [],
isset( $sql['join_conds'] ) ? $sql['join_conds'] : [] $sql['join_conds'] ?? []
); );
$this->assertLastSql( $sqlText ); $this->assertLastSql( $sqlText );
} }
public static function provideSelectRowCount() { public static function provideSelectRowCount() {
return [ return [
[ [
[ [
'tables' => 'table', 'tables' => 'table',
'field' => [ '*' ], 'field' => [ '*' ],
skipping to change at line 356 skipping to change at line 418
* @covers Wikimedia\Rdbms\Database::update * @covers Wikimedia\Rdbms\Database::update
* @covers Wikimedia\Rdbms\Database::makeUpdateOptions * @covers Wikimedia\Rdbms\Database::makeUpdateOptions
* @covers Wikimedia\Rdbms\Database::makeUpdateOptionsArray * @covers Wikimedia\Rdbms\Database::makeUpdateOptionsArray
*/ */
public function testUpdate( $sql, $sqlText ) { public function testUpdate( $sql, $sqlText ) {
$this->database->update( $this->database->update(
$sql['table'], $sql['table'],
$sql['values'], $sql['values'],
$sql['conds'], $sql['conds'],
__METHOD__, __METHOD__,
isset( $sql['options'] ) ? $sql['options'] : [] $sql['options'] ?? []
); );
$this->assertLastSql( $sqlText ); $this->assertLastSql( $sqlText );
} }
public static function provideUpdate() { public static function provideUpdate() {
return [ return [
[ [
[ [
'table' => 'table', 'table' => 'table',
'values' => [ 'field' => 'text', 'field2' => 'text2' ], 'values' => [ 'field' => 'text', 'field2' => 'text2' ],
skipping to change at line 524 skipping to change at line 586
/** /**
* @dataProvider provideInsert * @dataProvider provideInsert
* @covers Wikimedia\Rdbms\Database::insert * @covers Wikimedia\Rdbms\Database::insert
* @covers Wikimedia\Rdbms\Database::makeInsertOptions * @covers Wikimedia\Rdbms\Database::makeInsertOptions
*/ */
public function testInsert( $sql, $sqlText ) { public function testInsert( $sql, $sqlText ) {
$this->database->insert( $this->database->insert(
$sql['table'], $sql['table'],
$sql['rows'], $sql['rows'],
__METHOD__, __METHOD__,
isset( $sql['options'] ) ? $sql['options'] : [] $sql['options'] ?? []
); );
$this->assertLastSql( $sqlText ); $this->assertLastSql( $sqlText );
} }
public static function provideInsert() { public static function provideInsert() {
return [ return [
[ [
[ [
'table' => 'table', 'table' => 'table',
'rows' => [ 'field' => 'text', 'field2' = > 2 ], 'rows' => [ 'field' => 'text', 'field2' = > 2 ],
skipping to change at line 580 skipping to change at line 642
* @covers Wikimedia\Rdbms\Database::insertSelect * @covers Wikimedia\Rdbms\Database::insertSelect
* @covers Wikimedia\Rdbms\Database::nativeInsertSelect * @covers Wikimedia\Rdbms\Database::nativeInsertSelect
*/ */
public function testInsertSelect( $sql, $sqlTextNative, $sqlSelect, $sqlI nsert ) { public function testInsertSelect( $sql, $sqlTextNative, $sqlSelect, $sqlI nsert ) {
$this->database->insertSelect( $this->database->insertSelect(
$sql['destTable'], $sql['destTable'],
$sql['srcTable'], $sql['srcTable'],
$sql['varMap'], $sql['varMap'],
$sql['conds'], $sql['conds'],
__METHOD__, __METHOD__,
isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : $sql['insertOptions'] ?? [],
[], $sql['selectOptions'] ?? [],
isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : $sql['selectJoinConds'] ?? []
[],
isset( $sql['selectJoinConds'] ) ? $sql['selectJoinConds'
] : []
); );
$this->assertLastSql( $sqlTextNative ); $this->assertLastSql( $sqlTextNative );
$dbWeb = new DatabaseTestHelper( __CLASS__, [ 'cliMode' => false ] ); $dbWeb = new DatabaseTestHelper( __CLASS__, [ 'cliMode' => false ] );
$dbWeb->forceNextResult( [ $dbWeb->forceNextResult( [
array_flip( array_keys( $sql['varMap'] ) ) array_flip( array_keys( $sql['varMap'] ) )
] ); ] );
$dbWeb->insertSelect( $dbWeb->insertSelect(
$sql['destTable'], $sql['destTable'],
$sql['srcTable'], $sql['srcTable'],
$sql['varMap'], $sql['varMap'],
$sql['conds'], $sql['conds'],
__METHOD__, __METHOD__,
isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : $sql['insertOptions'] ?? [],
[], $sql['selectOptions'] ?? [],
isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : $sql['selectJoinConds'] ?? []
[],
isset( $sql['selectJoinConds'] ) ? $sql['selectJoinConds'
] : []
); );
$this->assertLastSqlDb( implode( '; ', [ $sqlSelect, 'BEGIN', $sq lInsert, 'COMMIT' ] ), $dbWeb ); $this->assertLastSqlDb( implode( '; ', [ $sqlSelect, 'BEGIN', $sq lInsert, 'COMMIT' ] ), $dbWeb );
} }
public static function provideInsertSelect() { public static function provideInsertSelect() {
return [ return [
[ [
[ [
'destTable' => 'insert_table', 'destTable' => 'insert_table',
'srcTable' => 'select_table', 'srcTable' => 'select_table',
'varMap' => [ 'field_insert' => 'field_se lect', 'field' => 'field2' ], 'varMap' => [ 'field_insert' => 'field_se lect', 'field' => 'field2' ],
'conds' => '*', 'conds' => '*',
], ],
"INSERT INTO insert_table " . "INSERT INTO insert_table " .
"(field_insert,field) " . "(field_insert,field) " .
"SELECT field_select,field2 " . "SELECT field_select,field2 " .
"FROM select_table WHERE *", "FROM select_table",
"SELECT field_select AS field_insert,field2 AS fi eld " . "SELECT field_select AS field_insert,field2 AS fi eld " .
"FROM select_table WHERE * FOR UPDATE", "FROM select_table FOR UPDATE",
"INSERT INTO insert_table (field_insert,field) VA LUES ('0','1')" "INSERT INTO insert_table (field_insert,field) VA LUES ('0','1')"
], ],
[ [
[ [
'destTable' => 'insert_table', 'destTable' => 'insert_table',
'srcTable' => 'select_table', 'srcTable' => 'select_table',
'varMap' => [ 'field_insert' => 'field_se lect', 'field' => 'field2' ], 'varMap' => [ 'field_insert' => 'field_se lect', 'field' => 'field2' ],
'conds' => [ 'field' => 2 ], 'conds' => [ 'field' => 2 ],
], ],
"INSERT INTO insert_table " . "INSERT INTO insert_table " .
skipping to change at line 696 skipping to change at line 758
} }
$dbWeb->forceNextResult( $rows ); $dbWeb->forceNextResult( $rows );
$dbWeb->insertSelect( $dbWeb->insertSelect(
'insert_table', 'insert_table',
'select_table', 'select_table',
[ 'field' => 'field2' ], [ 'field' => 'field2' ],
'*', '*',
__METHOD__ __METHOD__
); );
$this->assertLastSqlDb( implode( '; ', [ $this->assertLastSqlDb( implode( '; ', [
'SELECT field2 AS field FROM select_table WHERE * FOR U PDATE', 'SELECT field2 AS field FROM select_table FOR UPDATE ',
'BEGIN', 'BEGIN',
"INSERT INTO insert_table (field) VALUES ('" . implode( " '),('", range( 0, 9999 ) ) . "')", "INSERT INTO insert_table (field) VALUES ('" . implode( " '),('", range( 0, 9999 ) ) . "')",
"INSERT INTO insert_table (field) VALUES ('" . implode( " '),('", range( 10000, 19999 ) ) . "')", "INSERT INTO insert_table (field) VALUES ('" . implode( " '),('", range( 10000, 19999 ) ) . "')",
"INSERT INTO insert_table (field) VALUES ('" . implode( " '),('", range( 20000, 25000 ) ) . "')", "INSERT INTO insert_table (field) VALUES ('" . implode( " '),('", range( 20000, 25000 ) ) . "')",
'COMMIT' 'COMMIT'
] ), $dbWeb ); ] ), $dbWeb );
} }
/** /**
* @dataProvider provideReplace * @dataProvider provideReplace
skipping to change at line 1005 skipping to change at line 1067
*/ */
public function testUnionConditionPermutations( $params, $expect ) { public function testUnionConditionPermutations( $params, $expect ) {
if ( isset( $params['unionSupportsOrderAndLimit'] ) ) { if ( isset( $params['unionSupportsOrderAndLimit'] ) ) {
$this->database->setUnionSupportsOrderAndLimit( $params[' unionSupportsOrderAndLimit'] ); $this->database->setUnionSupportsOrderAndLimit( $params[' unionSupportsOrderAndLimit'] );
} }
$sql = trim( $this->database->unionConditionPermutations( $sql = trim( $this->database->unionConditionPermutations(
$params['table'], $params['table'],
$params['vars'], $params['vars'],
$params['permute_conds'], $params['permute_conds'],
isset( $params['extra_conds'] ) ? $params['extra_conds'] : '', $params['extra_conds'] ?? '',
'FNAME', 'FNAME',
isset( $params['options'] ) ? $params['options'] : [], $params['options'] ?? [],
isset( $params['join_conds'] ) ? $params['join_conds'] : $params['join_conds'] ?? []
[]
) ); ) );
$this->assertEquals( $expect, $sql ); $this->assertEquals( $expect, $sql );
} }
public static function provideUnionConditionPermutations() { public static function provideUnionConditionPermutations() {
// phpcs:disable Generic.Files.LineLength // phpcs:disable Generic.Files.LineLength
return [ return [
[ [
[ [
'table' => [ 'table1', 'table2' ], 'table' => [ 'table1', 'table2' ],
skipping to change at line 1427 skipping to change at line 1489
$this->database->rollback( __METHOD__ ); $this->database->rollback( __METHOD__ );
// phpcs:ignore Generic.Files.LineLength // phpcs:ignore Generic.Files.LineLength
$this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; RELEASE SAVEPOINT wikimedia_rdbms_atomic1; ROLLBACK' ); $this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; RELEASE SAVEPOINT wikimedia_rdbms_atomic1; ROLLBACK' );
$fname = __METHOD__; $fname = __METHOD__;
$triggerMap = [ $triggerMap = [
'-' => '-', '-' => '-',
IDatabase::TRIGGER_COMMIT => 'tCommit', IDatabase::TRIGGER_COMMIT => 'tCommit',
IDatabase::TRIGGER_ROLLBACK => 'tRollback' IDatabase::TRIGGER_ROLLBACK => 'tRollback'
]; ];
$pcCallback = function ( IDatabase $db ) use ( $fname ) {
$this->database->query( "SELECT 0", $fname );
};
$callback1 = function ( $trigger = '-' ) use ( $fname, $triggerMa p ) { $callback1 = function ( $trigger = '-' ) use ( $fname, $triggerMa p ) {
$this->database->query( "SELECT 1, {$triggerMap[$trigger] } AS t", $fname ); $this->database->query( "SELECT 1, {$triggerMap[$trigger] } AS t", $fname );
}; };
$callback2 = function ( $trigger = '-' ) use ( $fname, $triggerMa p ) { $callback2 = function ( $trigger = '-' ) use ( $fname, $triggerMa p ) {
$this->database->query( "SELECT 2, {$triggerMap[$trigger] } AS t", $fname ); $this->database->query( "SELECT 2, {$triggerMap[$trigger] } AS t", $fname );
}; };
$callback3 = function ( $trigger = '-' ) use ( $fname, $triggerMa p ) { $callback3 = function ( $trigger = '-' ) use ( $fname, $triggerMa p ) {
$this->database->query( "SELECT 3, {$triggerMap[$trigger] } AS t", $fname ); $this->database->query( "SELECT 3, {$triggerMap[$trigger] } AS t", $fname );
}; };
$this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE ); $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE );
$this->database->onTransactionPreCommitOrIdle( $callback1, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $pcCallback, __MET HOD__ );
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->assertLastSql( 'BEGIN; ROLLBACK' ); $this->assertLastSql( 'BEGIN; ROLLBACK' );
$this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE ); $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE );
$this->database->onTransactionIdle( $callback1, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback1, __METHOD_ _ );
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->assertLastSql( 'BEGIN; ROLLBACK' ); $this->assertLastSql( 'BEGIN; ROLLBACK' );
$this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE ); $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE );
$this->database->onTransactionResolution( $callback1, __METHOD__ ); $this->database->onTransactionResolution( $callback1, __METHOD__ );
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->assertLastSql( 'BEGIN; ROLLBACK; SELECT 1, tRollback AS t' ); $this->assertLastSql( 'BEGIN; ROLLBACK; SELECT 1, tRollback AS t' );
$this->database->startAtomic( __METHOD__ . '_outer' ); $this->database->startAtomic( __METHOD__ . '_outer' );
$this->database->onTransactionPreCommitOrIdle( $callback1, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $pcCallback, __MET HOD__ );
$this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE ); $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE );
$this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $pcCallback, __MET HOD__ );
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->database->onTransactionPreCommitOrIdle( $callback3, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $pcCallback, __MET HOD__ );
$this->database->endAtomic( __METHOD__ . '_outer' ); $this->database->endAtomic( __METHOD__ . '_outer' );
$this->assertLastSql( implode( "; ", [ $this->assertLastSql( implode( "; ", [
'BEGIN', 'BEGIN',
'SAVEPOINT wikimedia_rdbms_atomic1', 'SAVEPOINT wikimedia_rdbms_atomic1',
'ROLLBACK TO SAVEPOINT wikimedia_rdbms_atomic1', 'ROLLBACK TO SAVEPOINT wikimedia_rdbms_atomic1',
'SELECT 1, - AS t', 'SELECT 0',
'SELECT 3, - AS t', 'SELECT 0',
'COMMIT' 'COMMIT'
] ) ); ] ) );
$this->database->startAtomic( __METHOD__ . '_outer' ); $this->database->startAtomic( __METHOD__ . '_outer' );
$this->database->onTransactionIdle( $callback1, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback1, __METHOD_ _ );
$this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE ); $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE );
$this->database->onTransactionIdle( $callback2, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback2, __METHOD_ _ );
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->database->onTransactionIdle( $callback3, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback3, __METHOD_ _ );
$this->database->endAtomic( __METHOD__ . '_outer' ); $this->database->endAtomic( __METHOD__ . '_outer' );
$this->assertLastSql( implode( "; ", [ $this->assertLastSql( implode( "; ", [
'BEGIN', 'BEGIN',
'SAVEPOINT wikimedia_rdbms_atomic1', 'SAVEPOINT wikimedia_rdbms_atomic1',
'ROLLBACK TO SAVEPOINT wikimedia_rdbms_atomic1', 'ROLLBACK TO SAVEPOINT wikimedia_rdbms_atomic1',
'COMMIT', 'COMMIT',
'SELECT 1, tCommit AS t', 'SELECT 1, tCommit AS t',
'SELECT 3, tCommit AS t' 'SELECT 3, tCommit AS t'
] ) ); ] ) );
skipping to change at line 1630 skipping to change at line 1695
}; };
$callback3Called = null; $callback3Called = null;
$callback3 = function ( $trigger = '-' ) use ( $fname, &$callback 3Called ) { $callback3 = function ( $trigger = '-' ) use ( $fname, &$callback 3Called ) {
$callback3Called = $trigger; $callback3Called = $trigger;
$this->database->query( "SELECT 3", $fname ); $this->database->query( "SELECT 3", $fname );
}; };
$this->database->startAtomic( __METHOD__ . '_outer' ); $this->database->startAtomic( __METHOD__ . '_outer' );
$this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE ); $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE );
$this->database->startAtomic( __METHOD__ . '_inner' ); $this->database->startAtomic( __METHOD__ . '_inner' );
$this->database->onTransactionIdle( $callback1, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback1, __METHOD_ _ );
$this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ );
$this->database->onTransactionResolution( $callback3, __METHOD__ ); $this->database->onTransactionResolution( $callback3, __METHOD__ );
$this->database->endAtomic( __METHOD__ . '_inner' ); $this->database->endAtomic( __METHOD__ . '_inner' );
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->database->endAtomic( __METHOD__ . '_outer' ); $this->database->endAtomic( __METHOD__ . '_outer' );
$this->assertNull( $callback1Called ); $this->assertNull( $callback1Called );
$this->assertNull( $callback2Called ); $this->assertNull( $callback2Called );
$this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d ); $this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d );
// phpcs:ignore Generic.Files.LineLength // phpcs:ignore Generic.Files.LineLength
$this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; ROLLBACK TO SAVEPOINT wikimedia_rdbms_atomic1; COMMIT; SELECT 3' ); $this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; ROLLBACK TO SAVEPOINT wikimedia_rdbms_atomic1; COMMIT; SELECT 3' );
$callback1Called = null; $callback1Called = null;
$callback2Called = null; $callback2Called = null;
$callback3Called = null; $callback3Called = null;
$this->database->startAtomic( __METHOD__ . '_outer' ); $this->database->startAtomic( __METHOD__ . '_outer' );
$this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE ); $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE );
$this->database->startAtomic( __METHOD__ . '_inner', IDatabase::A TOMIC_CANCELABLE ); $this->database->startAtomic( __METHOD__ . '_inner', IDatabase::A TOMIC_CANCELABLE );
$this->database->onTransactionIdle( $callback1, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback1, __METHOD_ _ );
$this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ );
$this->database->onTransactionResolution( $callback3, __METHOD__ ); $this->database->onTransactionResolution( $callback3, __METHOD__ );
$this->database->endAtomic( __METHOD__ . '_inner' ); $this->database->endAtomic( __METHOD__ . '_inner' );
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->database->endAtomic( __METHOD__ . '_outer' ); $this->database->endAtomic( __METHOD__ . '_outer' );
$this->assertNull( $callback1Called ); $this->assertNull( $callback1Called );
$this->assertNull( $callback2Called ); $this->assertNull( $callback2Called );
$this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d ); $this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d );
// phpcs:ignore Generic.Files.LineLength // phpcs:ignore Generic.Files.LineLength
$this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; SAVEPOINT wikimedia_rdbms_atomic2; RELEASE SAVEPOINT wikimedia_rdbms_atomic2; RO LLBACK TO SAVEPOINT wikimedia_rdbms_atomic1; COMMIT; SELECT 3' ); $this->assertLastSql( 'BEGIN; SAVEPOINT wikimedia_rdbms_atomic1; SAVEPOINT wikimedia_rdbms_atomic2; RELEASE SAVEPOINT wikimedia_rdbms_atomic2; RO LLBACK TO SAVEPOINT wikimedia_rdbms_atomic1; COMMIT; SELECT 3' );
$callback1Called = null; $callback1Called = null;
$callback2Called = null; $callback2Called = null;
$callback3Called = null; $callback3Called = null;
$this->database->startAtomic( __METHOD__ . '_outer' ); $this->database->startAtomic( __METHOD__ . '_outer' );
$atomicId = $this->database->startAtomic( __METHOD__, IDatabase:: ATOMIC_CANCELABLE ); $atomicId = $this->database->startAtomic( __METHOD__, IDatabase:: ATOMIC_CANCELABLE );
$this->database->startAtomic( __METHOD__ . '_inner' ); $this->database->startAtomic( __METHOD__ . '_inner' );
$this->database->onTransactionIdle( $callback1, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback1, __METHOD_ _ );
$this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ );
$this->database->onTransactionResolution( $callback3, __METHOD__ ); $this->database->onTransactionResolution( $callback3, __METHOD__ );
$this->database->cancelAtomic( __METHOD__, $atomicId ); $this->database->cancelAtomic( __METHOD__, $atomicId );
$this->database->endAtomic( __METHOD__ . '_outer' ); $this->database->endAtomic( __METHOD__ . '_outer' );
$this->assertNull( $callback1Called ); $this->assertNull( $callback1Called );
$this->assertNull( $callback2Called ); $this->assertNull( $callback2Called );
$this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d ); $this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d );
$callback1Called = null; $callback1Called = null;
$callback2Called = null; $callback2Called = null;
$callback3Called = null; $callback3Called = null;
$this->database->startAtomic( __METHOD__ . '_outer' ); $this->database->startAtomic( __METHOD__ . '_outer' );
$atomicId = $this->database->startAtomic( __METHOD__, IDatabase:: ATOMIC_CANCELABLE ); $atomicId = $this->database->startAtomic( __METHOD__, IDatabase:: ATOMIC_CANCELABLE );
$this->database->startAtomic( __METHOD__ . '_inner' ); $this->database->startAtomic( __METHOD__ . '_inner' );
$this->database->onTransactionIdle( $callback1, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback1, __METHOD_ _ );
$this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ );
$this->database->onTransactionResolution( $callback3, __METHOD__ ); $this->database->onTransactionResolution( $callback3, __METHOD__ );
try { try {
$this->database->cancelAtomic( __METHOD__ . '_X', $atomic Id ); $this->database->cancelAtomic( __METHOD__ . '_X', $atomic Id );
} catch ( DBUnexpectedError $e ) { } catch ( DBUnexpectedError $e ) {
$m = __METHOD__; $m = __METHOD__;
$this->assertSame( $this->assertSame(
"Invalid atomic section ended (got {$m}_X but exp ected {$m}).", "Invalid atomic section ended (got {$m}_X but exp ected {$m}).",
$e->getMessage() $e->getMessage()
); );
} }
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->database->endAtomic( __METHOD__ . '_outer' ); $this->database->endAtomic( __METHOD__ . '_outer' );
$this->assertNull( $callback1Called ); $this->assertNull( $callback1Called );
$this->assertNull( $callback2Called ); $this->assertNull( $callback2Called );
$this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d ); $this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d );
$this->database->startAtomic( __METHOD__ . '_outer' ); $this->database->startAtomic( __METHOD__ . '_outer' );
$this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE ); $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE );
$this->database->startAtomic( __METHOD__ . '_inner' ); $this->database->startAtomic( __METHOD__ . '_inner' );
$this->database->onTransactionIdle( $callback1, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback1, __METHOD_ _ );
$this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ );
$this->database->onTransactionResolution( $callback3, __METHOD__ ); $this->database->onTransactionResolution( $callback3, __METHOD__ );
$this->database->cancelAtomic( __METHOD__ . '_inner' ); $this->database->cancelAtomic( __METHOD__ . '_inner' );
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->database->endAtomic( __METHOD__ . '_outer' ); $this->database->endAtomic( __METHOD__ . '_outer' );
$this->assertNull( $callback1Called ); $this->assertNull( $callback1Called );
$this->assertNull( $callback2Called ); $this->assertNull( $callback2Called );
$this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d ); $this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d );
$wrapper = TestingAccessWrapper::newFromObject( $this->database ) ; $wrapper = TestingAccessWrapper::newFromObject( $this->database ) ;
$callback1Called = null; $callback1Called = null;
$callback2Called = null; $callback2Called = null;
$callback3Called = null; $callback3Called = null;
$this->database->startAtomic( __METHOD__ . '_outer' ); $this->database->startAtomic( __METHOD__ . '_outer' );
$this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE ); $this->database->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCE LABLE );
$this->database->startAtomic( __METHOD__ . '_inner' ); $this->database->startAtomic( __METHOD__ . '_inner' );
$this->database->onTransactionIdle( $callback1, __METHOD__ ); $this->database->onTransactionCommitOrIdle( $callback1, __METHOD_ _ );
$this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ ); $this->database->onTransactionPreCommitOrIdle( $callback2, __METH OD__ );
$this->database->onTransactionResolution( $callback3, __METHOD__ ); $this->database->onTransactionResolution( $callback3, __METHOD__ );
$wrapper->trxStatus = Database::STATUS_TRX_ERROR; $wrapper->trxStatus = Database::STATUS_TRX_ERROR;
$this->database->cancelAtomic( __METHOD__ . '_inner' ); $this->database->cancelAtomic( __METHOD__ . '_inner' );
$this->database->cancelAtomic( __METHOD__ ); $this->database->cancelAtomic( __METHOD__ );
$this->database->endAtomic( __METHOD__ . '_outer' ); $this->database->endAtomic( __METHOD__ . '_outer' );
$this->assertNull( $callback1Called ); $this->assertNull( $callback1Called );
$this->assertNull( $callback2Called ); $this->assertNull( $callback2Called );
$this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d ); $this->assertEquals( IDatabase::TRIGGER_ROLLBACK, $callback3Calle d );
} }
skipping to change at line 1883 skipping to change at line 1948
try { try {
$this->database->delete( 'error', '1', __CLASS__ . '::SomeCaller' ); $this->database->delete( 'error', '1', __CLASS__ . '::SomeCaller' );
$this->fail( 'Expected exception not thrown' ); $this->fail( 'Expected exception not thrown' );
} catch ( DBError $e ) { } catch ( DBError $e ) {
$this->assertSame( 666, $e->errno ); $this->assertSame( 666, $e->errno );
} }
}; };
$this->database->setFlag( Database::DBO_TRX ); $this->database->setFlag( Database::DBO_TRX );
// Implicit transaction gets silently rolled back // Implicit transaction does not get silently rolled back
$this->database->begin( __METHOD__, Database::TRANSACTION_INTERNA L ); $this->database->begin( __METHOD__, Database::TRANSACTION_INTERNA L );
call_user_func( $doError ); call_user_func( $doError );
$this->database->delete( 'x', [ 'field' => 1 ], __METHOD__ ); try {
$this->database->commit( __METHOD__, Database::FLUSHING_INTERNAL $this->database->delete( 'x', [ 'field' => 1 ], __METHOD_
); _ );
// phpcs:ignore $this->fail( 'Expected exception not thrown' );
$this->assertLastSql( 'BEGIN; DELETE FROM error WHERE 1; ROLLBACK } catch ( DBTransactionError $e ) {
; BEGIN; DELETE FROM x WHERE field = \'1\'; COMMIT' ); $this->assertEquals(
'Cannot execute query from ' . __METHOD__ . ' whi
le transaction status is ERROR.',
$e->getMessage()
);
}
try {
$this->database->commit( __METHOD__, Database::FLUSHING_I
NTERNAL );
$this->fail( 'Expected exception not thrown' );
} catch ( DBTransactionError $e ) {
$this->assertEquals(
'Cannot execute query from ' . __METHOD__ . ' whi
le transaction status is ERROR.',
$e->getMessage()
);
}
$this->database->rollback( __METHOD__, Database::FLUSHING_INTERNA
L );
$this->assertLastSql( 'BEGIN; DELETE FROM error WHERE 1; ROLLBACK
' );
// ... unless there were prior writes // Likewise if there were prior writes
$this->database->begin( __METHOD__, Database::TRANSACTION_INTERNA L ); $this->database->begin( __METHOD__, Database::TRANSACTION_INTERNA L );
$this->database->delete( 'x', [ 'field' => 1 ], __METHOD__ ); $this->database->delete( 'x', [ 'field' => 1 ], __METHOD__ );
call_user_func( $doError ); call_user_func( $doError );
try { try {
$this->database->delete( 'x', [ 'field' => 1 ], __METHOD_ _ ); $this->database->delete( 'x', [ 'field' => 1 ], __METHOD_ _ );
$this->fail( 'Expected exception not thrown' ); $this->fail( 'Expected exception not thrown' );
} catch ( DBTransactionStateError $e ) { } catch ( DBTransactionStateError $e ) {
} }
$this->database->rollback( __METHOD__, Database::FLUSHING_INTERNA L ); $this->database->rollback( __METHOD__, Database::FLUSHING_INTERNA L );
// phpcs:ignore // phpcs:ignore
skipping to change at line 1976 skipping to change at line 2057
// phpcs:ignore // phpcs:ignore
$this->assertLastSql( 'BEGIN; DELETE FROM error WHERE 1; DELETE F ROM x WHERE field = \'1\'; COMMIT' ); $this->assertLastSql( 'BEGIN; DELETE FROM error WHERE 1; DELETE F ROM x WHERE field = \'1\'; COMMIT' );
} }
/** /**
* @covers \Wikimedia\Rdbms\Database::close * @covers \Wikimedia\Rdbms\Database::close
*/ */
public function testPrematureClose1() { public function testPrematureClose1() {
$fname = __METHOD__; $fname = __METHOD__;
$this->database->begin( __METHOD__ ); $this->database->begin( __METHOD__ );
$this->database->onTransactionIdle( function () use ( $fname ) { $this->database->onTransactionCommitOrIdle( function () use ( $fn ame ) {
$this->database->query( 'SELECT 1', $fname ); $this->database->query( 'SELECT 1', $fname );
} ); } );
$this->database->onTransactionResolution( function () use ( $fnam
e ) {
$this->database->query( 'SELECT 2', $fname );
} );
$this->database->delete( 'x', [ 'field' => 3 ], __METHOD__ ); $this->database->delete( 'x', [ 'field' => 3 ], __METHOD__ );
$this->database->close(); try {
$this->database->close();
$this->fail( 'Expected exception not thrown' );
} catch ( DBUnexpectedError $ex ) {
$this->assertSame(
"Wikimedia\Rdbms\Database::close: transaction is
still open (from $fname).",
$ex->getMessage()
);
}
$this->assertFalse( $this->database->isOpen() ); $this->assertFalse( $this->database->isOpen() );
$this->assertLastSql( 'BEGIN; DELETE FROM x WHERE field = \'3\'; COMMIT; SELECT 1' ); $this->assertLastSql( 'BEGIN; DELETE FROM x WHERE field = \'3\'; ROLLBACK; SELECT 2' );
$this->assertEquals( 0, $this->database->trxLevel() ); $this->assertEquals( 0, $this->database->trxLevel() );
} }
/** /**
* @covers \Wikimedia\Rdbms\Database::close * @covers \Wikimedia\Rdbms\Database::close
*/ */
public function testPrematureClose2() { public function testPrematureClose2() {
try { try {
$fname = __METHOD__; $fname = __METHOD__;
$this->database->startAtomic( __METHOD__ ); $this->database->startAtomic( __METHOD__ );
$this->database->onTransactionIdle( function () use ( $fn ame ) { $this->database->onTransactionCommitOrIdle( function () u se ( $fname ) {
$this->database->query( 'SELECT 1', $fname ); $this->database->query( 'SELECT 1', $fname );
} ); } );
$this->database->delete( 'x', [ 'field' => 3 ], __METHOD_ _ ); $this->database->delete( 'x', [ 'field' => 3 ], __METHOD_ _ );
$this->database->close(); $this->database->close();
$this->fail( 'Expected exception not thrown' ); $this->fail( 'Expected exception not thrown' );
} catch ( DBUnexpectedError $ex ) { } catch ( DBUnexpectedError $ex ) {
$this->assertSame( $this->assertSame(
'Wikimedia\Rdbms\Database::close: atomic sections ' . 'Wikimedia\Rdbms\Database::close: atomic sections ' .
'DatabaseSQLTest::testPrematureClose2 are still o pen.', 'DatabaseSQLTest::testPrematureClose2 are still o pen.',
$ex->getMessage() $ex->getMessage()
skipping to change at line 2047 skipping to change at line 2139
* @covers \Wikimedia\Rdbms\Database::close * @covers \Wikimedia\Rdbms\Database::close
*/ */
public function testPrematureClose4() { public function testPrematureClose4() {
$this->database->setFlag( IDatabase::DBO_TRX ); $this->database->setFlag( IDatabase::DBO_TRX );
$this->database->query( 'SELECT 1', __METHOD__ ); $this->database->query( 'SELECT 1', __METHOD__ );
$this->assertEquals( 1, $this->database->trxLevel() ); $this->assertEquals( 1, $this->database->trxLevel() );
$this->database->close(); $this->database->close();
$this->database->clearFlag( IDatabase::DBO_TRX ); $this->database->clearFlag( IDatabase::DBO_TRX );
$this->assertFalse( $this->database->isOpen() ); $this->assertFalse( $this->database->isOpen() );
$this->assertLastSql( 'BEGIN; SELECT 1; COMMIT' ); $this->assertLastSql( 'BEGIN; SELECT 1; ROLLBACK' );
$this->assertEquals( 0, $this->database->trxLevel() ); $this->assertEquals( 0, $this->database->trxLevel() );
} }
/**
* @covers Wikimedia\Rdbms\Database::selectFieldValues()
*/
public function testSelectFieldValues() {
$this->database->forceNextResult( [
(object)[ 'value' => 'row1' ],
(object)[ 'value' => 'row2' ],
(object)[ 'value' => 'row3' ],
] );
$this->assertSame(
[ 'row1', 'row2', 'row3' ],
$this->database->selectFieldValues( 'table', 'table.field
', 'conds', __METHOD__ )
);
$this->assertLastSql( 'SELECT table.field AS value FROM table WHE
RE conds' );
}
} }
 End of changes. 43 change blocks. 
59 lines changed or deleted 173 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)