jenkins-bot has submitted this change and it was merged. Change subject: MySQL method to find out view + fix fatal in tests ......................................................................
MySQL method to find out view + fix fatal in tests We were missing a method to list out views defined in a database. This patch adds in MysqlBase::isView() and MysqlBse::listViews(). Since listViews() cache its result in DatabaseBase::$allViews, we also introduce a final DatabaseBase::clearViewsCache() to let us clear the per process cache. Finally, fixed fatal error when duplicating VIEWs in MySQL. bug: 43571 Change-Id: I8650baa4b721fe69ea3e1d557dd76745c0c7754e --- M CREDITS M RELEASE-NOTES-1.22 M includes/db/Database.php M includes/db/DatabaseMysqlBase.php M tests/phpunit/MediaWikiTestCase.php M tests/phpunit/includes/db/DatabaseMysqlBaseTest.php 6 files changed, 182 insertions(+), 0 deletions(-) Approvals: Hashar: Looks good to me, approved jenkins-bot: Verified diff --git a/CREDITS b/CREDITS index 23636ae..01505b0 100644 --- a/CREDITS +++ b/CREDITS @@ -22,6 +22,7 @@ * church of emacs * Daniel Friesen * Daniel Kinzler +* Daniel Renfro * Danny B. * David McCabe * Derk-Jan Hartman diff --git a/RELEASE-NOTES-1.22 b/RELEASE-NOTES-1.22 index bc4de40..1c364ff 100644 --- a/RELEASE-NOTES-1.22 +++ b/RELEASE-NOTES-1.22 @@ -260,6 +260,9 @@ Previously in the "SimpleAntiSpam" extension by Ryan Schmidt. * populateRevisionLength.php maintenance script updated to also populate archive.ar_len field. +* (bug 43571) DatabaseMySQLBase learned to list views, optionally filtered by a + prefix. Also fixed PHPUnit test suite when using a MySQL backend containing + views. === Bug fixes in 1.22 === * (bug 47271) $wgContentHandlerUseDB should be set to false during the upgrade diff --git a/includes/db/Database.php b/includes/db/Database.php index cd907e9..284fd6c 100644 --- a/includes/db/Database.php +++ b/includes/db/Database.php @@ -301,6 +301,12 @@ */ protected $fileHandle = null; + /** + * @since 1.22 + * @var Process cache of VIEWs names in the database + */ + protected $allViews = null; + # ------------------------------------------------------------------------------ # Accessors # ------------------------------------------------------------------------------ @@ -3445,6 +3451,40 @@ } /** + * Reset the views process cache set by listViews() + * @since 1.22 + */ + final public function clearViewsCache() { + $this->allViews = null; + } + + /** + * Lists all the VIEWs in the database + * + * For caching purposes the list of all views should be stored in + * $this->allViews. The process cache can be cleared with clearViewsCache() + * + * @param string $prefix Only show VIEWs with this prefix, eg. unit_test_ + * @param string $fname Name of calling function + * @throws MWException + * @since 1.22 + */ + public function listViews( $prefix = null, $fname = __METHOD__ ) { + throw new MWException( 'DatabaseBase::listViews is not implemented in descendant class' ); + } + + /** + * Differentiates between a TABLE and a VIEW + * + * @param $name string: Name of the database-structure to test. + * @throws MWException + * @since 1.22 + */ + public function isView( $name ) { + throw new MWException( 'DatabaseBase::isView is not implemented in descendant class' ); + } + + /** * Convert a timestamp in one of the formats accepted by wfTimestamp() * to the format used for inserting into timestamp fields in this DBMS. * diff --git a/includes/db/DatabaseMysqlBase.php b/includes/db/DatabaseMysqlBase.php index 49579b6..26c9d24 100644 --- a/includes/db/DatabaseMysqlBase.php +++ b/includes/db/DatabaseMysqlBase.php @@ -996,6 +996,55 @@ return $status; } + /** + * Lists VIEWs in the database + * + * @param string $prefix Only show VIEWs with this prefix, eg. + * unit_test_, or $wgDBprefix. Default: null, would return all views. + * @param string $fname Name of calling function + * @return array + * @since 1.22 + */ + public function listViews( $prefix = null, $fname = __METHOD__ ) { + + if ( !isset( $this->allViews ) ) { + + // The name of the column containing the name of the VIEW + $propertyName = 'Tables_in_' . $this->mDBname; + + // Query for the VIEWS + $result = $this->query( 'SHOW FULL TABLES WHERE TABLE_TYPE = "VIEW"' ); + $this->allViews = array(); + while ( ($row = $this->fetchRow($result)) !== false ) { + array_push( $this->allViews, $row[$propertyName] ); + } + } + + if ( is_null($prefix) || $prefix === '' ) { + return $this->allViews; + } + + $filteredViews = array(); + foreach ( $this->allViews as $viewName ) { + // Does the name of this VIEW start with the table-prefix? + if ( strpos( $viewName, $prefix ) === 0 ) { + array_push( $filteredViews, $viewName ); + } + } + return $filteredViews; + } + + /** + * Differentiates between a TABLE and a VIEW. + * + * @param $name string: Name of the TABLE/VIEW to test + * @return bool + * @since 1.22 + */ + public function isView( $name, $prefix = null ) { + return in_array( $name, $this->listViews( $prefix ) ); + } + } diff --git a/tests/phpunit/MediaWikiTestCase.php b/tests/phpunit/MediaWikiTestCase.php index 8c849bc..6ce78b5 100644 --- a/tests/phpunit/MediaWikiTestCase.php +++ b/tests/phpunit/MediaWikiTestCase.php @@ -537,6 +537,12 @@ global $wgDBprefix; $tables = $db->listTables( $wgDBprefix, __METHOD__ ); + + if ( $db->getType() === 'mysql' ) { + # bug 43571: cannot clone VIEWs under MySQL + $views = $db->listViews( $wgDBprefix, __METHOD__ ); + $tables = array_diff( $tables, $views ); + } $tables = array_map( array( __CLASS__, 'unprefixTable' ), $tables ); // Don't duplicate test tables from the previous fataled run diff --git a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php index 134f856..ba63c09 100644 --- a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php +++ b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php @@ -123,4 +123,87 @@ return json_decode( '"' . $str . '"' ); } + function getMockForViews() { + $db = $this->getMockBuilder( 'DatabaseMysql' ) + ->disableOriginalConstructor() + ->setMethods( array( 'fetchRow', 'query' ) ) + ->getMock(); + + $db->expects( $this->any() ) + ->method( 'query' ) + ->with( $this->anything() ) + ->will( + $this->returnValue( null ) + ); + + $db->expects( $this->any() ) + ->method( 'fetchRow' ) + ->with( $this->anything() ) + ->will( $this->onConsecutiveCalls( + array( 'Tables_in_' => 'view1' ), + array( 'Tables_in_' => 'view2' ), + array( 'Tables_in_' => 'myview' ), + false # no more rows + )); + return $db; + } + /** + * @covers DatabaseMysqlBase::listViews + */ + function testListviews() { + $db = $this->getMockForViews(); + + // The first call populate an internal cache of views + $this->assertEquals( array( 'view1', 'view2', 'myview'), + $db->listViews() ); + $this->assertEquals( array( 'view1', 'view2', 'myview'), + $db->listViews() ); + + // Prefix filtering + $this->assertEquals( array( 'view1', 'view2' ), + $db->listViews( 'view' ) ); + $this->assertEquals( array( 'myview' ), + $db->listViews( 'my' ) ); + $this->assertEquals( array(), + $db->listViews( 'UNUSED_PREFIX' ) ); + $this->assertEquals( array( 'view1', 'view2', 'myview'), + $db->listViews( '' ) ); + } + + /** + * @covers DatabaseMysqlBase::isView + * @dataProvider provideViewExistanceChecks + */ + function testIsView( $isView, $viewName ) { + $db = $this->getMockForViews(); + + switch( $isView ) { + case true: + $this->assertTrue( $db->isView( $viewName ), + "$viewName should be considered a view" ); + break; + + case false: + $this->assertFalse( $db->isView( $viewName ), + "$viewName has not been defined as a view" ); + break; + } + + } + + function provideViewExistanceChecks() { + return array( + // format: whether it is a view, view name + array( true, 'view1' ), + array( true, 'view2' ), + array( true, 'myview' ), + + array( false, 'user' ), + + array( false, 'view10' ), + array( false, 'my' ), + array( false, 'OH_MY_GOD' ), # they killed kenny! + ); + } + } -- To view, visit https://gerrit.wikimedia.org/r/65301 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I8650baa4b721fe69ea3e1d557dd76745c0c7754e Gerrit-PatchSet: 17 Gerrit-Project: mediawiki/core Gerrit-Branch: master Gerrit-Owner: AlephNull <dren...@vistaprint.com> Gerrit-Reviewer: AlephNull <dren...@vistaprint.com> Gerrit-Reviewer: Brian Wolff <bawolff...@gmail.com> Gerrit-Reviewer: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Hashar <has...@free.fr> Gerrit-Reviewer: Physikerwelt <w...@physikerwelt.de> Gerrit-Reviewer: Springle <sprin...@wikimedia.org> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits