Merge "rdbms: implement IDatabase::serverIsReadOnly() for sqlite/mssql"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 28 Jun 2019 22:18:33 +0000 (22:18 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 28 Jun 2019 22:18:33 +0000 (22:18 +0000)
1  2 
includes/libs/rdbms/database/DatabaseMssql.php
includes/libs/rdbms/database/DatabaseSqlite.php

@@@ -28,7 -28,6 +28,7 @@@
  namespace Wikimedia\Rdbms;
  
  use Exception;
 +use RuntimeException;
  use stdClass;
  use Wikimedia\AtEase\AtEase;
  
@@@ -375,6 -374,17 +375,17 @@@ class DatabaseMssql extends Database 
                return $statementOnly;
        }
  
+       public function serverIsReadOnly() {
+               $encDatabase = $this->addQuotes( $this->getDBname() );
+               $res = $this->query(
+                       "SELECT IS_READ_ONLY FROM SYS.DATABASES WHERE NAME = $encDatabase",
+                       __METHOD__
+               );
+               $row = $this->fetchObject( $res );
+               return $row ? (bool)$row->IS_READ_ONLY : false;
+       }
        /**
         * @return int
         */
                $this->query( 'ROLLBACK TRANSACTION ' . $this->addIdentifierQuotes( $identifier ), $fname );
        }
  
 -      /**
 -       * Begin a transaction, committing any previously open transaction
 -       * @param string $fname
 -       */
        protected function doBegin( $fname = __METHOD__ ) {
 -              sqlsrv_begin_transaction( $this->conn );
 -              $this->trxLevel = 1;
 +              if ( !sqlsrv_begin_transaction( $this->conn ) ) {
 +                      $this->reportQueryError( $this->lastError(), $this->lastErrno(), 'BEGIN', $fname );
 +              }
        }
  
        /**
         * @param string $fname
         */
        protected function doCommit( $fname = __METHOD__ ) {
 -              sqlsrv_commit( $this->conn );
 -              $this->trxLevel = 0;
 +              if ( !sqlsrv_commit( $this->conn ) ) {
 +                      $this->reportQueryError( $this->lastError(), $this->lastErrno(), 'COMMIT', $fname );
 +              }
        }
  
        /**
         * @param string $fname
         */
        protected function doRollback( $fname = __METHOD__ ) {
 -              sqlsrv_rollback( $this->conn );
 -              $this->trxLevel = 0;
 +              if ( !sqlsrv_rollback( $this->conn ) ) {
 +                      $this->queryLogger->error(
 +                              "{fname}\t{db_server}\t{errno}\t{error}\t",
 +                              $this->getLogContext( [
 +                                      'errno' => $this->lastErrno(),
 +                                      'error' => $this->lastError(),
 +                                      'fname' => $fname,
 +                                      'trace' => ( new RuntimeException() )->getTraceAsString()
 +                              ] )
 +                      );
 +              }
        }
  
        /**
@@@ -173,18 -173,8 +173,8 @@@ class DatabaseSqlite extends Database 
                        throw new DBExpectedError( $this, __CLASS__ . ": domain schemas are not supported." );
                }
  
-               $fileName = self::generateFileName( $this->dbDir, $dbName );
-               if ( !is_readable( $fileName ) ) {
-                       $error = "SQLite database file not readable";
-                       $this->connLogger->error(
-                               "Error connecting to {db_server}: {error}",
-                               $this->getLogContext( [ 'method' => __METHOD__, 'error' => $error ] )
-                       );
-                       throw new DBConnectionError( $this, $error );
-               }
                // Only $dbName is used, the other parameters are irrelevant for SQLite databases
-               $this->openFile( $fileName, $dbName, $tablePrefix );
+               $this->openFile( self::generateFileName( $this->dbDir, $dbName ), $dbName, $tablePrefix );
        }
  
        /**
         * @throws DBConnectionError
         */
        protected function openFile( $fileName, $dbName, $tablePrefix ) {
+               if ( !$this->hasMemoryPath() && !is_readable( $fileName ) ) {
+                       $error = "SQLite database file not readable";
+                       $this->connLogger->error(
+                               "Error connecting to {db_server}: {error}",
+                               $this->getLogContext( [ 'method' => __METHOD__, 'error' => $error ] )
+                       );
+                       throw new DBConnectionError( $this, $error );
+               }
                $this->dbPath = $fileName;
                try {
                        $this->conn = new PDO(
                return false;
        }
  
+       public function serverIsReadOnly() {
+               return ( !$this->hasMemoryPath() && !is_writable( $this->dbPath ) );
+       }
+       /**
+        * @return bool
+        */
+       private function hasMemoryPath() {
+               return ( strpos( $this->dbPath, ':memory:' ) === 0 );
+       }
        /**
         * @return string Wikitext of a link to the server software's web site
         */
                } else {
                        $this->query( 'BEGIN', $fname );
                }
 -              $this->trxLevel = 1;
        }
  
        /**