The actual error is always in English, so wrap it in ltr element
[lhc/web/wiklou.git] / includes / db / Database.php
index d29d142..4d75379 100644 (file)
@@ -28,11 +28,10 @@ interface DatabaseType {
         *
         * @return string
         */
-       public function getType();
+       function getType();
 
        /**
         * Open a connection to the database. Usually aborts on failure
-        * If the failFunction is set to a non-zero integer, returns success
         *
         * @param $server String: database server host
         * @param $user String: database user name
@@ -41,17 +40,17 @@ interface DatabaseType {
         * @return bool
         * @throws DBConnectionError
         */
-       public function open( $server, $user, $password, $dbName );
+       function open( $server, $user, $password, $dbName );
 
        /**
         * The DBMS-dependent part of query()
-        * @todo @fixme Make this private someday
+        * @todo Fixme: Make this private someday
         *
         * @param  $sql String: SQL query.
         * @return Result object to feed to fetchObject, fetchRow, ...; or false on failure
         * @private
         */
-       /*private*/ function doQuery( $sql );
+       function doQuery( $sql );
 
        /**
         * Fetch the next row from the given result object, in object form.
@@ -62,7 +61,7 @@ interface DatabaseType {
         * @return Row object
         * @throws DBUnexpectedError Thrown if the database returns an error
         */
-       public function fetchObject( $res );
+       function fetchObject( $res );
 
        /**
         * Fetch the next row from the given result object, in associative array
@@ -72,7 +71,7 @@ interface DatabaseType {
         * @return Row object
         * @throws DBUnexpectedError Thrown if the database returns an error
         */
-       public function fetchRow( $res );
+       function fetchRow( $res );
 
        /**
         * Get the number of rows in a result object
@@ -80,7 +79,7 @@ interface DatabaseType {
         * @param $res Mixed: A SQL result
         * @return int
         */
-       public function numRows( $res );
+       function numRows( $res );
 
        /**
         * Get the number of fields in a result object
@@ -89,7 +88,7 @@ interface DatabaseType {
         * @param $res Mixed: A SQL result
         * @return int
         */
-       public function numFields( $res );
+       function numFields( $res );
 
        /**
         * Get a field name in a result object
@@ -99,7 +98,7 @@ interface DatabaseType {
         * @param $n Integer
         * @return string
         */
-       public function fieldName( $res, $n );
+       function fieldName( $res, $n );
 
        /**
         * Get the inserted value of an auto-increment row
@@ -113,7 +112,7 @@ interface DatabaseType {
         *
         * @return int
         */
-       public function insertId();
+       function insertId();
 
        /**
         * Change the position of the cursor in a result object
@@ -122,7 +121,7 @@ interface DatabaseType {
         * @param $res Mixed: A SQL result
         * @param $row Mixed: Either MySQL row or ResultWrapper
         */
-       public function dataSeek( $res, $row );
+       function dataSeek( $res, $row );
 
        /**
         * Get the last error number
@@ -130,7 +129,7 @@ interface DatabaseType {
         *
         * @return int
         */
-       public function lastErrno();
+       function lastErrno();
 
        /**
         * Get a description of the last error
@@ -138,7 +137,7 @@ interface DatabaseType {
         *
         * @return string
         */
-       public function lastError();
+       function lastError();
 
        /**
         * mysql_fetch_field() wrapper
@@ -147,7 +146,16 @@ interface DatabaseType {
         * @param $table string: table name
         * @param $field string: field name
         */
-       public function fieldInfo( $table, $field );
+       function fieldInfo( $table, $field );
+
+       /**
+        * Get information about an index into an object
+        * @param $table string: Table name
+        * @param $index string: Index name
+        * @param $fname string: Calling function name
+        * @return Mixed: Database-specific index description class or false if the index does not exist
+        */
+       function indexInfo( $table, $index, $fname = 'Database::indexInfo' );
 
        /**
         * Get the number of rows affected by the last write query
@@ -155,7 +163,7 @@ interface DatabaseType {
         *
         * @return int
         */
-       public function affectedRows();
+       function affectedRows();
 
        /**
         * Wrapper for addslashes()
@@ -163,7 +171,7 @@ interface DatabaseType {
         * @param $s string: to be slashed.
         * @return string: slashed string.
         */
-       public function strencode( $s );
+       function strencode( $s );
 
        /**
         * Returns a wikitext link to the DB's website, e.g.,
@@ -173,7 +181,7 @@ interface DatabaseType {
         *
         * @return string: wikitext of a link to the server software's web site
         */
-       public static function getSoftwareLink();
+       static function getSoftwareLink();
 
        /**
         * A string describing the current software version, like from
@@ -181,7 +189,7 @@ interface DatabaseType {
         *
         * @return string: Version information from the database server.
         */
-       public function getServerVersion();
+       function getServerVersion();
 
        /**
         * A string describing the current software version, and possibly
@@ -190,7 +198,7 @@ interface DatabaseType {
         *
         * @return string: Version information from the database server
         */
-       public function getServerInfo();
+       function getServerInfo();
 }
 
 /**
@@ -210,7 +218,6 @@ abstract class DatabaseBase implements DatabaseType {
        protected $mServer, $mUser, $mPassword, $mConn = null, $mDBname;
        protected $mOpened = false;
 
-       protected $mFailFunction;
        protected $mTablePrefix;
        protected $mFlags;
        protected $mTrxLevel = 0;
@@ -235,14 +242,6 @@ abstract class DatabaseBase implements DatabaseType {
                return $this->getServerVersion();
        }
 
-       /**
-        * Fail function, takes a Database as a parameter
-        * Set to false for default, 1 for ignore errors
-        */
-       function failFunction( $function = null ) {
-               return wfSetVar( $this->mFailFunction, $function );
-       }
-
        /**
         * Boolean, controls output of large amounts of debug information
         */
@@ -289,7 +288,7 @@ abstract class DatabaseBase implements DatabaseType {
        }
 
        function tablePrefix( $prefix = null ) {
-               return wfSetVar( $this->mTablePrefix, $prefix );
+               return wfSetVar( $this->mTablePrefix, $prefix, true );
        }
 
        /**
@@ -487,12 +486,11 @@ abstract class DatabaseBase implements DatabaseType {
         * @param $user String: database user name
         * @param $password String: database user password
         * @param $dbName String: database name
-        * @param $failFunction
         * @param $flags
         * @param $tablePrefix String: database table prefixes. By default use the prefix gave in LocalSettings.php
         */
        function __construct( $server = false, $user = false, $password = false, $dbName = false,
-               $failFunction = false, $flags = 0, $tablePrefix = 'get from global'
+               $flags = 0, $tablePrefix = 'get from global'
        ) {
                global $wgOut, $wgDBprefix, $wgCommandLineMode;
 
@@ -500,8 +498,6 @@ abstract class DatabaseBase implements DatabaseType {
                if ( !isset( $wgOut ) ) {
                        $wgOut = null;
                }
-
-               $this->mFailFunction = $failFunction;
                $this->mFlags = $flags;
 
                if ( $this->mFlags & DBO_DEFAULT ) {
@@ -512,13 +508,6 @@ abstract class DatabaseBase implements DatabaseType {
                        }
                }
 
-               /*
-               // Faster read-only access
-               if ( wfReadOnly() ) {
-                       $this->mFlags |= DBO_PERSISTENT;
-                       $this->mFlags &= ~DBO_TRX;
-               }*/
-
                /** Get the default table prefix*/
                if ( $tablePrefix == 'get from global' ) {
                        $this->mTablePrefix = $wgDBprefix;
@@ -537,12 +526,32 @@ abstract class DatabaseBase implements DatabaseType {
         * @param $user String: database user name
         * @param $password String: database user password
         * @param $dbName String: database name
-        * @param failFunction
         * @param $flags
         */
-       static function newFromParams( $server, $user, $password, $dbName, $failFunction = false, $flags = 0 ) {
+       static function newFromParams( $server, $user, $password, $dbName, $flags = 0 ) {
                wfDeprecated( __METHOD__ );
-               return new DatabaseMysql( $server, $user, $password, $dbName, $failFunction, $flags );
+               return new DatabaseMysql( $server, $user, $password, $dbName, $flags );
+       }
+
+       /**
+        * Given a DB type, construct the name of the appropriate child class of
+        * DatabaseBase. This is designed to replace all of the manual stuff like:
+        *      $class = 'Database' . ucfirst( strtolower( $type ) );
+        * as well as validate against the canonical list of DB types we have
+        *
+        * @param $dbType String A possible DB type
+        * @return DatabaseBase subclass or null
+        */
+       public final static function classFromType( $dbType ) {
+               $canonicalDBTypes = array(
+                       'mysql', 'postgres', 'sqlite', 'oracle', 'mssql', 'ibm_db2'
+               );
+               $dbType = strtolower( $dbType );
+               if( in_array( $dbType, $canonicalDBTypes ) ) {
+                       return 'Database' . ucfirst( $dbType );
+               } else {
+                       return null;
+               }
        }
 
        protected function installErrorHandler() {
@@ -589,16 +598,8 @@ abstract class DatabaseBase implements DatabaseType {
                        $error = $myError;
                }
 
-               if ( $this->mFailFunction ) {
-                       # Legacy error handling method
-                       if ( !is_int( $this->mFailFunction ) ) {
-                               $ff = $this->mFailFunction;
-                               $ff( $this, $error );
-                       }
-               } else {
-                       # New method
-                       throw new DBConnectionError( $this, $error );
-               }
+               # New method
+               throw new DBConnectionError( $this, $error );
        }
 
        /**
@@ -617,7 +618,7 @@ abstract class DatabaseBase implements DatabaseType {
         *     comment (you can use __METHOD__ or add some extra info)
         * @param  $tempIgnore Boolean:   Whether to avoid throwing an exception on errors...
         *     maybe best to catch the exception instead?
-        * @return true for a successful write query, ResultWrapper object for a successful read query,
+        * @return boolean or ResultWrapper. true for a successful write query, ResultWrapper object for a successful read query,
         *     or false on failure if $tempIgnore set
         * @throws DBQueryError Thrown when the database returns an error of any kind
         */
@@ -654,7 +655,7 @@ abstract class DatabaseBase implements DatabaseType {
                # Add a comment for easy SHOW PROCESSLIST interpretation
                # if ( $fname ) {
                        global $wgUser;
-                       if ( is_object( $wgUser ) && !( $wgUser instanceof StubObject ) ) {
+                       if ( is_object( $wgUser ) && $wgUser->mDataLoaded ) {
                                $userName = $wgUser->getName();
                                if ( mb_strlen( $userName ) > 15 ) {
                                        $userName = mb_substr( $userName, 0, 15 ) . '...';
@@ -1025,7 +1026,7 @@ abstract class DatabaseBase implements DatabaseType {
        /**
         * SELECT wrapper
         *
-        * @param $table   Mixed:  Array or string, table name(s) (prefix auto-added)
+        * @param $table   Mixed:  Array or string, table name(s) (prefix auto-added). Array keys are table aliases (optional)
         * @param $vars    Mixed:  Array or string, field name(s) to be retrieved
         * @param $conds   Mixed:  Array or string, condition(s) for WHERE
         * @param $fname   String: Calling function name (use __METHOD__) for logs/profiling
@@ -1048,7 +1049,7 @@ abstract class DatabaseBase implements DatabaseType {
                        if ( !empty( $join_conds ) || ( isset( $options['USE INDEX'] ) && is_array( @$options['USE INDEX'] ) ) ) {
                                $from = ' FROM ' . $this->tableNamesWithUseIndexOrJOIN( $table, @$options['USE INDEX'], $join_conds );
                        } else {
-                               $from = ' FROM ' . implode( ',', array_map( array( &$this, 'tableName' ), $table ) );
+                               $from = ' FROM ' . implode( ',', $this->tableNamesWithAlias( $table ) );
                        }
                } elseif ( $table != '' ) {
                        if ( $table { 0 } == ' ' ) {
@@ -1197,35 +1198,6 @@ abstract class DatabaseBase implements DatabaseType {
                }
        }
 
-
-       /**
-        * Get information about an index into an object
-        * Returns false if the index does not exist
-        */
-       function indexInfo( $table, $index, $fname = 'DatabaseBase::indexInfo' ) {
-               # SHOW INDEX works in MySQL 3.23.58, but SHOW INDEXES does not.
-               # SHOW INDEX should work for 3.x and up:
-               # http://dev.mysql.com/doc/mysql/en/SHOW_INDEX.html
-               $table = $this->tableName( $table );
-               $index = $this->indexName( $index );
-               $sql = 'SHOW INDEX FROM ' . $table;
-               $res = $this->query( $sql, $fname );
-
-               if ( !$res ) {
-                       return null;
-               }
-
-               $result = array();
-
-               while ( $row = $this->fetchObject( $res ) ) {
-                       if ( $row->Key_name == $index ) {
-                               $result[] = $row;
-                       }
-               }
-
-               return empty( $result ) ? false : $result;
-       }
-
        /**
         * Query whether a given table exists
         */
@@ -1617,6 +1589,39 @@ abstract class DatabaseBase implements DatabaseType {
                return $retVal;
        }
 
+       /**
+        * Get an aliased table name
+        * e.g. tableName AS newTableName
+        *
+        * @param $name string Table name, see tableName()
+        * @param $alias string Alias (optional)
+        * @return string SQL name for aliased table. Will not alias a table to its own name
+        */
+       public function tableNameWithAlias( $name, $alias = false ) {
+               if ( !$alias || $alias == $name ) {
+                       return $this->tableName( $name );
+               } else {
+                       return $this->tableName( $name ) . ' `' . $alias . '`';
+               }
+       }
+
+       /**
+        * Gets an array of aliased table names
+        *
+        * @param $tables array( [alias] => table )
+        * @return array of strings, see tableNameWithAlias()
+        */
+       public function tableNamesWithAlias( $tables ) {
+               $retval = array();
+               foreach ( $tables as $alias => $table ) {
+                       if ( is_numeric( $alias ) ) {
+                               $alias = $table;
+                       }
+                       $retval[] = $this->tableNameWithAlias( $table, $alias );
+               }
+               return $retval;
+       }
+
        /**
         * @private
         */
@@ -1626,35 +1631,37 @@ abstract class DatabaseBase implements DatabaseType {
                $use_index_safe = is_array( $use_index ) ? $use_index : array();
                $join_conds_safe = is_array( $join_conds ) ? $join_conds : array();
 
-               foreach ( $tables as $table ) {
+               foreach ( $tables as $alias => $table ) {
+                       if ( !is_string( $alias ) ) {
+                               // No alias? Set it equal to the table name
+                               $alias = $table;
+                       }
                        // Is there a JOIN and INDEX clause for this table?
-                       if ( isset( $join_conds_safe[$table] ) && isset( $use_index_safe[$table] ) ) {
-                               $tableClause = $join_conds_safe[$table][0] . ' ' . $this->tableName( $table );
-                               $tableClause .= ' ' . $this->useIndexClause( implode( ',', (array)$use_index_safe[$table] ) );
-                               $on = $this->makeList( (array)$join_conds_safe[$table][1], LIST_AND );
-
+                       if ( isset( $join_conds_safe[$alias] ) && isset( $use_index_safe[$alias] ) ) {
+                               $tableClause = $join_conds_safe[$alias][0] . ' ' . $this->tableNameWithAlias( $table, $alias );
+                               $tableClause .= ' ' . $this->useIndexClause( implode( ',', (array)$use_index_safe[$alias] ) );
+                               $on = $this->makeList( (array)$join_conds_safe[$alias][1], LIST_AND );
                                if ( $on != '' ) {
                                        $tableClause .= ' ON (' . $on . ')';
                                }
 
                                $retJOIN[] = $tableClause;
                        // Is there an INDEX clause?
-                       } else if ( isset( $use_index_safe[$table] ) ) {
-                               $tableClause = $this->tableName( $table );
-                               $tableClause .= ' ' . $this->useIndexClause( implode( ',', (array)$use_index_safe[$table] ) );
+                       } else if ( isset( $use_index_safe[$alias] ) ) {
+                               $tableClause = $this->tableNameWithAlias( $table, $alias );
+                               $tableClause .= ' ' . $this->useIndexClause( implode( ',', (array)$use_index_safe[$alias] ) );
                                $ret[] = $tableClause;
                        // Is there a JOIN clause?
-                       } else if ( isset( $join_conds_safe[$table] ) ) {
-                               $tableClause = $join_conds_safe[$table][0] . ' ' . $this->tableName( $table );
-                               $on = $this->makeList( (array)$join_conds_safe[$table][1], LIST_AND );
-
+                       } else if ( isset( $join_conds_safe[$alias] ) ) {
+                               $tableClause = $join_conds_safe[$alias][0] . ' ' . $this->tableNameWithAlias( $table, $alias );
+                               $on = $this->makeList( (array)$join_conds_safe[$alias][1], LIST_AND );
                                if ( $on != '' ) {
                                        $tableClause .= ' ON (' . $on . ')';
                                }
 
                                $retJOIN[] = $tableClause;
                        } else {
-                               $tableClause = $this->tableName( $table );
+                               $tableClause = $this->tableNameWithAlias( $table, $alias );
                                $ret[] = $tableClause;
                        }
                }
@@ -1701,6 +1708,27 @@ abstract class DatabaseBase implements DatabaseType {
                }
        }
 
+       /**
+        * Quotes an identifier using `backticks` or "double quotes" depending on the database type.
+        * MySQL uses `backticks` while basically everything else uses double quotes.
+        * Since MySQL is the odd one out here the double quotes are our generic
+        * and we implement backticks in DatabaseMysql.
+        */      
+       public function addIdentifierQuotes( $s ) {
+               return '"' . str_replace( '"', '""', $s ) . '"';
+       }
+
+       /**
+        * Backwards compatibility, identifier quoting originated in DatabasePostgres
+        * which used quote_ident which does not follow our naming conventions
+        * was renamed to addIdentifierQuotes.
+        * @deprecated use addIdentifierQuotes
+        */
+       function quote_ident( $s ) {
+               wfDeprecated( __METHOD__ );
+               return $this->addIdentifierQuotes( $s );
+       }
+
        /**
         * Escape string for safe LIKE usage.
         * WARNING: you should almost never use this function directly,
@@ -2264,6 +2292,16 @@ abstract class DatabaseBase implements DatabaseType {
        function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseBase::duplicateTableStructure' ) {
                throw new MWException( 'DatabaseBase::duplicateTableStructure is not implemented in descendant class' );
        }
+       
+       /**
+        * List all tables on the database
+        *
+        * @param $prefix Only show tables with this prefix, e.g. mw_
+        * @param $fname String: calling function name
+        */
+       function listTables( $prefix = null, $fname = 'DatabaseBase::listTables' ) {
+               throw new MWException( 'DatabaseBase::listTables is not implemented in descendant class' );
+       }
 
        /**
         * Return MW-style timestamp used for MySQL schema
@@ -2332,7 +2370,7 @@ abstract class DatabaseBase implements DatabaseType {
                $res = $this->query( "SHOW STATUS LIKE '{$which}'" );
                $status = array();
 
-               while ( $row = $this->fetchObject( $res ) ) {
+               foreach ( $res as $row ) {
                        $status[$row->Variable_name] = $row->Value;
                }
 
@@ -2374,13 +2412,12 @@ abstract class DatabaseBase implements DatabaseType {
         *              using $filename
         */
        function sourceFile( $filename, $lineCallback = false, $resultCallback = false, $fname = false ) {
+               wfSuppressWarnings();
                $fp = fopen( $filename, 'r' );
+               wfRestoreWarnings();
 
                if ( false === $fp ) {
-                       if ( !defined( "MEDIAWIKI_INSTALL" ) )
-                               throw new MWException( "Could not open \"{$filename}\".\n" );
-                       else
-                               return "Could not open \"{$filename}\".\n";
+                       throw new MWException( "Could not open \"{$filename}\".\n" );
                }
 
                if ( !$fname ) {
@@ -2391,12 +2428,8 @@ abstract class DatabaseBase implements DatabaseType {
                        $error = $this->sourceStream( $fp, $lineCallback, $resultCallback, $fname );
                }
                catch ( MWException $e ) {
-                       if ( defined( "MEDIAWIKI_INSTALL" ) ) {
-                               $error = $e->getMessage();
-                       } else {
-                               fclose( $fp );
-                               throw $e;
-                       }
+                       fclose( $fp );
+                       throw $e;
                }
 
                fclose( $fp );
@@ -2497,6 +2530,32 @@ abstract class DatabaseBase implements DatabaseType {
                return true;
        }
 
+       /**
+        * Database independent variable replacement, replaces a set of named variables
+        * in a sql statement with the contents of their global variables.
+        * Supports '{$var}' `{$var}` and / *$var* / (without the spaces) style variables
+        * 
+        * '{$var}' should be used for text and is passed through the database's addQuotes method
+        * `{$var}` should be used for identifiers (eg: table and database names), it is passed through
+        *          the database's addIdentifierQuotes method which can be overridden if the database
+        *          uses something other than backticks.
+        * / *$var* / is just encoded, besides traditional dbprefix and tableoptions it's use should be avoided
+        * 
+        * @param $ins String: SQL statement to replace variables in
+        * @param $varnames Array: Array of global variable names to replace
+        * @return String The new SQL statement with variables replaced
+        */
+       protected function replaceGlobalVars( $ins, $varnames ) {
+               foreach ( $varnames as $var ) {
+                       if ( isset( $GLOBALS[$var] ) ) {
+                               $ins = str_replace( '\'{$' . $var . '}\'', $this->addQuotes( $GLOBALS[$var] ), $ins ); // replace '{$var}'
+                               $ins = str_replace( '`{$' . $var . '}`', $this->addIdentifierQuotes( $GLOBALS[$var] ), $ins ); // replace `{$var}`
+                               $ins = str_replace( '/*$' . $var . '*/', $this->strencode( $GLOBALS[$var] ) , $ins ); // replace /*$var*/
+                       }
+               }
+               return $ins;
+       }
+
        /**
         * Replace variables in sourced SQL
         */
@@ -2507,15 +2566,7 @@ abstract class DatabaseBase implements DatabaseType {
                        'wgDBadminuser', 'wgDBadminpassword', 'wgDBTableOptions',
                );
 
-               // Ordinary variables
-               foreach ( $varnames as $var ) {
-                       if ( isset( $GLOBALS[$var] ) ) {
-                               $val = addslashes( $GLOBALS[$var] ); // FIXME: safety check?
-                               $ins = str_replace( '{$' . $var . '}', $val, $ins );
-                               $ins = str_replace( '/*$' . $var . '*/`', '`' . $val, $ins );
-                               $ins = str_replace( '/*$' . $var . '*/', $val, $ins );
-                       }
-               }
+               $ins = $this->replaceGlobalVars( $ins, $varnames );
 
                // Table prefixes
                $ins = preg_replace_callback( '!/\*(?:\$wgDBprefix|_)\*/([a-zA-Z_0-9]*)!',
@@ -2602,6 +2653,20 @@ abstract class DatabaseBase implements DatabaseType {
                return true;
        }
 
+       /**
+        * Delete a table
+        */
+       public function dropTable( $tableName, $fName = 'DatabaseBase::dropTable' ) {
+               if( !$this->tableExists( $tableName ) ) {
+                       return false;
+               }
+               $sql = "DROP TABLE " . $this->tableName( $tableName );
+               if( $this->cascadingDeletes() ) {
+                       $sql .= " CASCADE";
+               }
+               return $this->query( $sql, $fName );
+       }
+
        /**
         * Get search engine class. All subclasses of this need to implement this
         * if they wish to use searching.
@@ -2612,6 +2677,17 @@ abstract class DatabaseBase implements DatabaseType {
                return 'SearchEngineDummy';
        }
 
+       /**
+        * Find out when 'infinity' is. Most DBMSes support this. This is a special
+        * keyword for timestamps in PostgreSQL, and works with CHAR(14) as well
+        * because "i" sorts after all numbers.
+        *
+        * @return String
+        */
+       public function getInfinity() {
+               return 'infinity';
+       }
+
        /**
         * Allow or deny "big selects" for this session only. This is done by setting
         * the sql_big_selects session variable.
@@ -2668,57 +2744,33 @@ class Blob {
 }
 
 /**
- * Utility class.
+ * Base for all database-specific classes representing information about database fields
  * @ingroup Database
  */
-class MySQLField {
-       private $name, $tablename, $default, $max_length, $nullable,
-               $is_pk, $is_unique, $is_multiple, $is_key, $type;
-
-       function __construct ( $info ) {
-               $this->name = $info->name;
-               $this->tablename = $info->table;
-               $this->default = $info->def;
-               $this->max_length = $info->max_length;
-               $this->nullable = !$info->not_null;
-               $this->is_pk = $info->primary_key;
-               $this->is_unique = $info->unique_key;
-               $this->is_multiple = $info->multiple_key;
-               $this->is_key = ( $this->is_pk || $this->is_unique || $this->is_multiple );
-               $this->type = $info->type;
-       }
-
-       function name() {
-               return $this->name;
-       }
-
-       function tableName() {
-               return $this->tableName;
-       }
-
-       function defaultValue() {
-               return $this->default;
-       }
-
-       function maxLength() {
-               return $this->max_length;
-       }
-
-       function nullable() {
-               return $this->nullable;
-       }
+interface Field {
+       /**
+        * Field name
+        * @return string
+        */
+       function name();
 
-       function isKey() {
-               return $this->is_key;
-       }
+       /**
+        * Name of table this field belongs to
+        * @return string
+        */
+       function tableName();
 
-       function isMultipleKey() {
-               return $this->is_multiple;
-       }
+       /**
+        * Database type
+        * @return string
+        */
+       function type();
 
-       function type() {
-               return $this->type;
-       }
+       /**
+        * Whether this field can store NULL values
+        * @return bool
+        */
+       function isNullable();
 }
 
 /******************************************************************************
@@ -2822,6 +2874,8 @@ class DBConnectionError extends DBError {
                        $this->error = $this->db->getProperty( 'mServer' );
                }
 
+               $this->error = Html::element( 'span', array( 'dir' => 'ltr' ), $this->error );
+
                $noconnect = "<p><strong>$sorry</strong><br />$again</p><p><small>$info</small></p>";
                $text = str_replace( '$1', $this->error, $noconnect );
 
@@ -2861,7 +2915,7 @@ class DBConnectionError extends DBError {
        }
 
        function searchForm() {
-               global $wgSitename, $wgServer, $wgLang, $wgInputEncoding;
+               global $wgSitename, $wgServer, $wgLang;
 
                $usegoogle = "You can try searching via Google in the meantime.";
                $outofdate = "Note that their indexes of our content may be out of date.";
@@ -2875,20 +2929,23 @@ class DBConnectionError extends DBError {
 
                $search = htmlspecialchars( @$_REQUEST['search'] );
 
+               $server = htmlspecialchars( $wgServer );
+               $sitename = htmlspecialchars( $wgSitename );
+
                $trygoogle = <<<EOT
 <div style="margin: 1.5em">$usegoogle<br />
 <small>$outofdate</small></div>
 <!-- SiteSearch Google -->
 <form method="get" action="http://www.google.com/search" id="googlesearch">
-       <input type="hidden" name="domains" value="$wgServer" />
+       <input type="hidden" name="domains" value="$server" />
        <input type="hidden" name="num" value="50" />
-       <input type="hidden" name="ie" value="$wgInputEncoding" />
-       <input type="hidden" name="oe" value="$wgInputEncoding" />
+       <input type="hidden" name="ie" value="UTF-8" />
+       <input type="hidden" name="oe" value="UTF-8" />
 
        <input type="text" name="q" size="31" maxlength="255" value="$search" />
        <input type="submit" name="btnG" value="$googlesearch" />
   <div>
-       <input type="radio" name="sitesearch" id="gwiki" value="$wgServer" checked="checked" /><label for="gwiki">$wgSitename</label>
+       <input type="radio" name="sitesearch" id="gwiki" value="$server" checked="checked" /><label for="gwiki">$sitename</label>
        <input type="radio" name="sitesearch" id="gWWW" value="" /><label for="gWWW">WWW</label>
   </div>
 </form>
@@ -2897,8 +2954,8 @@ EOT;
                return $trygoogle;
        }
 
-       function fileCachedPage() {
-               global $wgTitle, $title, $wgLang, $wgOut;
+       private function fileCachedPage() {
+               global $wgTitle, $wgLang, $wgOut;
 
                if ( $wgOut->isDisabled() ) {
                        return; // Done already?
@@ -2907,13 +2964,11 @@ EOT;
                $mainpage = 'Main Page';
 
                if ( $wgLang instanceof Language ) {
-                       $mainpage    = htmlspecialchars( $wgLang->getMessage( 'mainpage' ) );
+                       $mainpage = htmlspecialchars( $wgLang->getMessage( 'mainpage' ) );
                }
 
                if ( $wgTitle ) {
                        $t =& $wgTitle;
-               } elseif ( $title ) {
-                       $t = Title::newFromURL( $title );
                } else {
                        $t = Title::newFromText( $mainpage );
                }