*/
protected $fileHandle = null;
+ /**
+ * @since 1.22
+ * @var Process cache of VIEWs names in the database
+ */
+ protected $allViews = null;
+
# ------------------------------------------------------------------------------
# Accessors
# ------------------------------------------------------------------------------
* connection object, by specifying no parameters to __construct(). This
* feature is deprecated and should be removed.
*
- * FIXME: The long list of formal parameters here is not really appropriate
- * for MySQL, and not at all appropriate for any other DBMS. It should be
- * replaced by named parameters as in DatabaseBase::factory().
- *
* DatabaseBase subclasses should not be constructed directly in external
* code. DatabaseBase::factory() should be used instead.
*
- * @param string $server database server host
- * @param string $user database user name
- * @param string $password database user password
- * @param string $dbName database name
- * @param $flags
- * @param string $tablePrefix database table prefixes. By default use the prefix gave in LocalSettings.php
- * @param bool $foreign disable some operations specific to local databases
+ * @param array Parameters passed from DatabaseBase::factory()
*/
- function __construct( $server = false, $user = false, $password = false, $dbName = false,
- $flags = 0, $tablePrefix = 'get from global', $foreign = false
- ) {
+ function __construct( $params = null ) {
global $wgDBprefix, $wgCommandLineMode, $wgDebugDBTransactions;
$this->mTrxAtomicLevels = new SplStack;
- $this->mFlags = $flags;
+ if ( is_array( $params ) ) { // MW 1.22
+ $server = $params['host'];
+ $user = $params['user'];
+ $password = $params['password'];
+ $dbName = $params['dbname'];
+ $flags = $params['flags'];
+ $tablePrefix = $params['tablePrefix'];
+ $foreign = $params['foreign'];
+ } else { // legacy calling pattern
+ wfDeprecated( __METHOD__ . " method called without parameter array.", "1.22" );
+ $args = func_get_args();
+ $server = isset( $args[0] ) ? $args[0] : false;
+ $user = isset( $args[1] ) ? $args[1] : false;
+ $password = isset( $args[2] ) ? $args[2] : false;
+ $dbName = isset( $args[3] ) ? $args[3] : false;
+ $flags = isset( $args[4] ) ? $args[4] : 0;
+ $tablePrefix = isset( $args[5] ) ? $args[5] : 'get from global';
+ $foreign = isset( $args[6] ) ? $args[6] : false;
+ }
+
+ $this->mFlags = $flags;
if ( $this->mFlags & DBO_DEFAULT ) {
if ( $wgCommandLineMode ) {
$this->mFlags &= ~DBO_TRX;
$class = 'Database' . ucfirst( $driver );
if ( class_exists( $class ) && is_subclass_of( $class, 'DatabaseBase' ) ) {
- return new $class(
- isset( $p['host'] ) ? $p['host'] : false,
- isset( $p['user'] ) ? $p['user'] : false,
- isset( $p['password'] ) ? $p['password'] : false,
- isset( $p['dbname'] ) ? $p['dbname'] : false,
- isset( $p['flags'] ) ? $p['flags'] : 0,
- isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : 'get from global',
- isset( $p['foreign'] ) ? $p['foreign'] : false
+ $params = array(
+ 'host' => isset( $p['host'] ) ? $p['host'] : false,
+ 'user' => isset( $p['user'] ) ? $p['user'] : false,
+ 'password' => isset( $p['password'] ) ? $p['password'] : false,
+ 'dbname' => isset( $p['dbname'] ) ? $p['dbname'] : false,
+ 'flags' => isset( $p['flags'] ) ? $p['flags'] : 0,
+ 'tablePrefix' => isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : 'get from global',
+ 'foreign' => isset( $p['foreign'] ) ? $p['foreign'] : false
);
+ return new $class( $params );
} else {
return null;
}
throw new MWException( 'DatabaseBase::listTables is not implemented in descendant class' );
}
+ /**
+ * 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.
*/
class FakeDatabaseMysqlBase extends DatabaseMysqlBase {
// From DatabaseBase
+ function __construct() {}
protected function closeConnection() {}
protected function doQuery( $sql ) {}
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!
+ );
+ }
+
}