*/
namespace Wikimedia\Rdbms;
+use NullLockManager;
use PDO;
use PDOException;
use Exception;
/** @var bool Whether full text is enabled */
private static $fulltextEnabled = null;
- /** @var string Directory */
+ /** @var string|null Directory */
protected $dbDir;
/** @var string File name for SQLite database file */
protected $dbPath;
$this->queryLogger->warning( "Invalid SQLite transaction mode provided." );
}
- $this->lockMgr = new FSLockManager( [
- 'domain' => $lockDomain,
- 'lockDirectory' => "{$this->dbDir}/locks"
- ] );
+ if ( $this->hasProcessMemoryPath() ) {
+ $this->lockMgr = new NullLockManager( [ 'domain' => $lockDomain ] );
+ } else {
+ $this->lockMgr = new FSLockManager( [
+ 'domain' => $lockDomain,
+ 'lockDirectory' => is_string( $this->dbDir )
+ ? "{$this->dbDir}/locks"
+ : dirname( $this->dbPath ) . "/locks"
+ ] );
+ }
parent::__construct( $p );
}
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->hasProcessMemoryPath() && !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;
}
- $r = $res instanceof ResultWrapper ? $res->result : $res;
- $this->lastAffectedRowCount = $r->rowCount();
- $res = new ResultWrapper( $this, $r->fetchAll() );
+ $resource = ResultWrapper::unwrap( $res );
+ $this->lastAffectedRowCount = $resource->rowCount();
+ $res = new ResultWrapper( $this, $resource->fetchAll() );
return $res;
}
*/
function freeResult( $res ) {
if ( $res instanceof ResultWrapper ) {
- $res->result = null;
- } else {
- $res = null;
+ $res->free();
}
}
* @return stdClass|bool
*/
function fetchObject( $res ) {
- if ( $res instanceof ResultWrapper ) {
- $r =& $res->result;
- } else {
- $r =& $res;
- }
+ $resource =& ResultWrapper::unwrap( $res );
- $cur = current( $r );
+ $cur = current( $resource );
if ( is_array( $cur ) ) {
- next( $r );
+ next( $resource );
$obj = new stdClass;
foreach ( $cur as $k => $v ) {
if ( !is_numeric( $k ) ) {
* @return array|bool
*/
function fetchRow( $res ) {
- if ( $res instanceof ResultWrapper ) {
- $r =& $res->result;
- } else {
- $r =& $res;
- }
- $cur = current( $r );
+ $resource =& ResultWrapper::unwrap( $res );
+ $cur = current( $resource );
if ( is_array( $cur ) ) {
- next( $r );
+ next( $resource );
return $cur;
}
*/
function numRows( $res ) {
// false does not implement Countable
- $r = $res instanceof ResultWrapper ? $res->result : $res;
+ $resource = ResultWrapper::unwrap( $res );
- return is_array( $r ) ? count( $r ) : 0;
+ return is_array( $resource ) ? count( $resource ) : 0;
}
/**
* @return int
*/
function numFields( $res ) {
- $r = $res instanceof ResultWrapper ? $res->result : $res;
- if ( is_array( $r ) && count( $r ) > 0 ) {
+ $resource = ResultWrapper::unwrap( $res );
+ if ( is_array( $resource ) && count( $resource ) > 0 ) {
// The size of the result array is twice the number of fields. (T67578)
- return count( $r[0] ) / 2;
+ return count( $resource[0] ) / 2;
} else {
// If the result is empty return 0
return 0;
* @return bool
*/
function fieldName( $res, $n ) {
- $r = $res instanceof ResultWrapper ? $res->result : $res;
- if ( is_array( $r ) ) {
- $keys = array_keys( $r[0] );
+ $resource = ResultWrapper::unwrap( $res );
+ if ( is_array( $resource ) ) {
+ $keys = array_keys( $resource[0] );
return $keys[$n];
}
* @param int $row
*/
function dataSeek( $res, $row ) {
- if ( $res instanceof ResultWrapper ) {
- $r =& $res->result;
- } else {
- $r =& $res;
- }
- reset( $r );
+ $resource =& ResultWrapper::unwrap( $res );
+ reset( $resource );
if ( $row > 0 ) {
for ( $i = 0; $i < $row; $i++ ) {
- next( $r );
+ next( $resource );
}
}
}
return false;
}
+ public function serverIsReadOnly() {
+ return ( !$this->hasProcessMemoryPath() && !is_writable( $this->dbPath ) );
+ }
+
+ /**
+ * @return bool
+ */
+ private function hasProcessMemoryPath() {
+ return ( strpos( $this->dbPath, ':memory:' ) === 0 );
+ }
+
/**
* @return string Wikitext of a link to the server software's web site
*/
}
public function lock( $lockName, $method, $timeout = 5 ) {
- if ( !is_dir( "{$this->dbDir}/locks" ) ) { // create dir as needed
- if ( !is_writable( $this->dbDir ) || !mkdir( "{$this->dbDir}/locks" ) ) {
- throw new DBError( $this, "Cannot create directory \"{$this->dbDir}/locks\"." );
- }
+ // Give better error message for permission problems than just returning false
+ if (
+ !is_dir( "{$this->dbDir}/locks" ) &&
+ ( !is_writable( $this->dbDir ) || !mkdir( "{$this->dbDir}/locks" ) )
+ ) {
+ throw new DBError( $this, "Cannot create directory \"{$this->dbDir}/locks\"." );
}
return $this->lockMgr->lock( [ $lockName ], LockManager::LOCK_EX, $timeout )->isOK();
}
public function unlock( $lockName, $method ) {
- return $this->lockMgr->unlock( [ $lockName ], LockManager::LOCK_EX )->isOK();
+ return $this->lockMgr->unlock( [ $lockName ], LockManager::LOCK_EX )->isGood();
}
/**