Remove support for PHP extension 'mysql' (not mysqli!)
[lhc/web/wiklou.git] / includes / libs / rdbms / database / Database.php
index 9875d93..323c147 100644 (file)
@@ -317,8 +317,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         *   - flags : Optional bitfield of DBO_* constants that define connection, protocol,
         *      buffering, and transaction behavior. It is STRONGLY adviced to leave the DBO_DEFAULT
         *      flag in place UNLESS this this database simply acts as a key/value store.
-        *   - driver: Optional name of a specific DB client driver. For MySQL, there is the old
-        *      'mysql' driver and the newer 'mysqli' driver.
+        *   - driver: Optional name of a specific DB client driver. For MySQL, there is only the
+        *      'mysqli' driver; the old one 'mysql' has been removed.
         *   - variables: Optional map of session variables to set after connecting. This can be
         *      used to adjust lock timeouts or encoding modes and the like.
         *   - connLogger: Optional PSR-3 logger interface instance.
@@ -337,7 +337,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         */
        final public static function factory( $dbType, $p = [] ) {
                static $canonicalDBTypes = [
-                       'mysql' => [ 'mysqli', 'mysql' ],
+                       'mysql' => [ 'mysqli' ],
                        'postgres' => [],
                        'sqlite' => [],
                        'oracle' => [],
@@ -345,7 +345,6 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                ];
                static $classAliases = [
                        'DatabaseMssql' => DatabaseMssql::class,
-                       'DatabaseMysql' => DatabaseMysql::class,
                        'DatabaseMysqli' => DatabaseMysqli::class,
                        'DatabaseSqlite' => DatabaseSqlite::class,
                        'DatabasePostgres' => DatabasePostgres::class
@@ -394,7 +393,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        $p['variables'] = isset( $p['variables'] ) ? $p['variables'] : [];
                        $p['tablePrefix'] = isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : '';
                        $p['schema'] = isset( $p['schema'] ) ? $p['schema'] : '';
-                       $p['cliMode'] = isset( $p['cliMode'] ) ? $p['cliMode'] : ( PHP_SAPI === 'cli' );
+                       $p['cliMode'] = isset( $p['cliMode'] )
+                               ? $p['cliMode']
+                               : ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' );
                        $p['agent'] = isset( $p['agent'] ) ? $p['agent'] : '';
                        if ( !isset( $p['connLogger'] ) ) {
                                $p['connLogger'] = new \Psr\Log\NullLogger();
@@ -461,9 +462,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        protected function ignoreErrors( $ignoreErrors = null ) {
                $res = $this->getFlag( self::DBO_IGNORE );
                if ( $ignoreErrors !== null ) {
-                       $ignoreErrors
-                               ? $this->setFlag( self::DBO_IGNORE )
-                               : $this->clearFlag( self::DBO_IGNORE );
+                       // setFlag()/clearFlag() do not allow DBO_IGNORE changes for sanity
+                       if ( $ignoreErrors ) {
+                               $this->mFlags |= self::DBO_IGNORE;
+                       } else {
+                               $this->mFlags &= ~self::DBO_IGNORE;
+                       }
                }
 
                return $res;
@@ -621,6 +625,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        public function setFlag( $flag, $remember = self::REMEMBER_NOTHING ) {
+               if ( ( $flag & self::DBO_IGNORE ) ) {
+                       throw new \UnexpectedValueException( "Modifying DBO_IGNORE is not allowed." );
+               }
+
                if ( $remember === self::REMEMBER_PRIOR ) {
                        array_push( $this->priorFlags, $this->mFlags );
                }
@@ -628,6 +636,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        public function clearFlag( $flag, $remember = self::REMEMBER_NOTHING ) {
+               if ( ( $flag & self::DBO_IGNORE ) ) {
+                       throw new \UnexpectedValueException( "Modifying DBO_IGNORE is not allowed." );
+               }
+
                if ( $remember === self::REMEMBER_PRIOR ) {
                        array_push( $this->priorFlags, $this->mFlags );
                }
@@ -897,6 +909,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                }
 
                if ( $isWrite ) {
+                       if ( $this->getLBInfo( 'replica' ) === true ) {
+                               throw new DBError(
+                                       $this,
+                                       'Write operations are not allowed on replica database connections.'
+                               );
+                       }
                        # In theory, non-persistent writes are allowed in read-only mode, but due to things
                        # like https://bugs.mysql.com/bug.php?id=33669 that might not work anyway...
                        $reason = $this->getReadOnlyReason();
@@ -2019,9 +2037,19 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
                        if ( is_array( $table ) ) {
                                // A parenthesized group
-                               $joinedTable = '('
-                                       . $this->tableNamesWithIndexClauseOrJOIN( $table, $use_index, $ignore_index, $join_conds )
-                                       . ')';
+                               if ( count( $table ) > 1 ) {
+                                       $joinedTable = '('
+                                               . $this->tableNamesWithIndexClauseOrJOIN( $table, $use_index, $ignore_index, $join_conds )
+                                               . ')';
+                               } else {
+                                       // Degenerate case
+                                       $innerTable = reset( $table );
+                                       $innerAlias = key( $table );
+                                       $joinedTable = $this->tableNameWithAlias(
+                                               $innerTable,
+                                               is_string( $innerAlias ) ? $innerAlias : $innerTable
+                                       );
+                               }
                        } else {
                                $joinedTable = $this->tableNameWithAlias( $table, $alias );
                        }
@@ -3363,6 +3391,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                $fname = __METHOD__,
                callable $inputCallback = null
        ) {
+               $delimiterReset = new ScopedCallback(
+                       function ( $delimiter ) {
+                               $this->delimiter = $delimiter;
+                       },
+                       [ $this->delimiter ]
+               );
                $cmd = '';
 
                while ( !feof( $fp ) ) {
@@ -3391,7 +3425,15 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        if ( $done || feof( $fp ) ) {
                                $cmd = $this->replaceVars( $cmd );
 
-                               if ( !$inputCallback || call_user_func( $inputCallback, $cmd ) ) {
+                               if ( $inputCallback ) {
+                                       $callbackResult = call_user_func( $inputCallback, $cmd );
+
+                                       if ( is_string( $callbackResult ) || !$callbackResult ) {
+                                               $cmd = $callbackResult;
+                                       }
+                               }
+
+                               if ( $cmd ) {
                                        $res = $this->query( $cmd, $fname );
 
                                        if ( $resultCallback ) {
@@ -3408,6 +3450,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        }
                }
 
+               ScopedCallback::consume( $delimiterReset );
                return true;
        }