summaryrefslogtreecommitdiff
path: root/includes/db/DatabaseSqlite.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/db/DatabaseSqlite.php')
-rw-r--r--includes/db/DatabaseSqlite.php163
1 files changed, 84 insertions, 79 deletions
diff --git a/includes/db/DatabaseSqlite.php b/includes/db/DatabaseSqlite.php
index dd2e813e..ed86bab1 100644
--- a/includes/db/DatabaseSqlite.php
+++ b/includes/db/DatabaseSqlite.php
@@ -29,8 +29,14 @@ class DatabaseSqlite extends DatabaseBase {
/** @var bool Whether full text is enabled */
private static $fulltextEnabled = null;
+ /** @var string Directory */
+ protected $dbDir;
+
/** @var string File name for SQLite database file */
- public $mDatabaseFile;
+ protected $dbPath;
+
+ /** @var string Transaction mode */
+ protected $trxMode;
/** @var int The number of rows affected as an integer */
protected $mAffectedRows;
@@ -44,35 +50,63 @@ class DatabaseSqlite extends DatabaseBase {
/** @var FSLockManager (hopefully on the same server as the DB) */
protected $lockMgr;
- function __construct( $p = null ) {
+ /**
+ * Additional params include:
+ * - dbDirectory : directory containing the DB and the lock file directory
+ * [defaults to $wgSQLiteDataDir]
+ * - dbFilePath : use this to force the path of the DB file
+ * - trxMode : one of (deferred, immediate, exclusive)
+ * @param array $p
+ */
+ function __construct( array $p ) {
global $wgSharedDB, $wgSQLiteDataDir;
- if ( !is_array( $p ) ) { // legacy calling pattern
- wfDeprecated( __METHOD__ . " method called without parameter array.", "1.22" );
- $args = func_get_args();
- $p = array(
- 'host' => 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',
- 'schema' => 'get from global',
- 'foreign' => isset( $args[6] ) ? $args[6] : false
- );
- }
- $this->mDBname = $p['dbname'];
- parent::__construct( $p );
- // parent doesn't open when $user is false, but we can work with $dbName
- if ( $p['dbname'] && !$this->isOpen() ) {
- if ( $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] ) ) {
- if ( $wgSharedDB ) {
- $this->attachDatabase( $wgSharedDB );
+ $this->dbDir = isset( $p['dbDirectory'] ) ? $p['dbDirectory'] : $wgSQLiteDataDir;
+
+ if ( isset( $p['dbFilePath'] ) ) {
+ $this->mFlags = isset( $p['flags'] ) ? $p['flags'] : 0;
+ // Standalone .sqlite file mode
+ $this->openFile( $p['dbFilePath'] );
+ // @FIXME: clean up base constructor so this can call super instead
+ $this->mTrxAtomicLevels = new SplStack;
+ } else {
+ $this->mDBname = $p['dbname'];
+ // Stock wiki mode using standard file names per DB
+ parent::__construct( $p );
+ // parent doesn't open when $user is false, but we can work with $dbName
+ if ( $p['dbname'] && !$this->isOpen() ) {
+ if ( $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] ) ) {
+ if ( $wgSharedDB ) {
+ $this->attachDatabase( $wgSharedDB );
+ }
}
}
}
- $this->lockMgr = new FSLockManager( array( 'lockDirectory' => "$wgSQLiteDataDir/locks" ) );
+ $this->trxMode = isset( $p['trxMode'] ) ? strtoupper( $p['trxMode'] ) : null;
+ if ( $this->trxMode &&
+ !in_array( $this->trxMode, array( 'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE' ) )
+ ) {
+ $this->trxMode = null;
+ wfWarn( "Invalid SQLite transaction mode provided." );
+ }
+
+ $this->lockMgr = new FSLockManager( array( 'lockDirectory' => "{$this->dbDir}/locks" ) );
+ }
+
+ /**
+ * @param string $filename
+ * @param array $p Options map; supports:
+ * - flags : (same as __construct counterpart)
+ * - trxMode : (same as __construct counterpart)
+ * - dbDirectory : (same as __construct counterpart)
+ * @return DatabaseSqlite
+ * @since 1.25
+ */
+ public static function newStandaloneInstance( $filename, array $p = array() ) {
+ $p['dbFilePath'] = $filename;
+
+ return new self( $p );
}
/**
@@ -103,10 +137,8 @@ class DatabaseSqlite extends DatabaseBase {
* @return PDO
*/
function open( $server, $user, $pass, $dbName ) {
- global $wgSQLiteDataDir;
-
$this->close();
- $fileName = self::generateFileName( $wgSQLiteDataDir, $dbName );
+ $fileName = self::generateFileName( $this->dbDir, $dbName );
if ( !is_readable( $fileName ) ) {
$this->mConn = false;
throw new DBConnectionError( $this, "SQLite database not accessible" );
@@ -123,10 +155,10 @@ class DatabaseSqlite extends DatabaseBase {
* @throws DBConnectionError
* @return PDO|bool SQL connection or false if failed
*/
- function openFile( $fileName ) {
+ protected function openFile( $fileName ) {
$err = false;
- $this->mDatabaseFile = $fileName;
+ $this->dbPath = $fileName;
try {
if ( $this->mFlags & DBO_PERSISTENT ) {
$this->mConn = new PDO( "sqlite:$fileName", '', '',
@@ -144,8 +176,8 @@ class DatabaseSqlite extends DatabaseBase {
}
$this->mOpened = !!$this->mConn;
- # set error codes only, don't raise exceptions
if ( $this->mOpened ) {
+ # Set error codes only, don't raise exceptions
$this->mConn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
# Enforce LIKE to be case sensitive, just like MySQL
$this->query( 'PRAGMA case_sensitive_like = 1' );
@@ -157,6 +189,14 @@ class DatabaseSqlite extends DatabaseBase {
}
/**
+ * @return string SQLite DB file path
+ * @since 1.25
+ */
+ public function getDbFilePath() {
+ return $this->dbPath;
+ }
+
+ /**
* Does not actually close the connection, just destroys the reference for GC to do its work
* @return bool
*/
@@ -206,8 +246,7 @@ class DatabaseSqlite extends DatabaseBase {
$cachedResult = false;
$table = 'dummy_search_test';
- $db = new DatabaseSqliteStandalone( ':memory:' );
-
+ $db = self::newStandaloneInstance( ':memory:' );
if ( $db->query( "CREATE VIRTUAL TABLE $table USING FTS3(dummy_field)", __METHOD__, true ) ) {
$cachedResult = 'FTS3';
}
@@ -223,14 +262,13 @@ class DatabaseSqlite extends DatabaseBase {
* @param string $name Database name to be used in queries like
* SELECT foo FROM dbname.table
* @param bool|string $file Database file name. If omitted, will be generated
- * using $name and $wgSQLiteDataDir
+ * using $name and configured data directory
* @param string $fname Calling function name
* @return ResultWrapper
*/
function attachDatabase( $name, $file = false, $fname = __METHOD__ ) {
- global $wgSQLiteDataDir;
if ( !$file ) {
- $file = self::generateFileName( $wgSQLiteDataDir, $name );
+ $file = self::generateFileName( $this->dbDir, $name );
}
$file = $this->addQuotes( $file );
@@ -712,37 +750,14 @@ class DatabaseSqlite extends DatabaseBase {
}
protected function doBegin( $fname = '' ) {
- if ( $this->mTrxLevel == 1 ) {
- $this->commit( __METHOD__ );
- }
- try {
- $this->mConn->beginTransaction();
- } catch ( PDOException $e ) {
- throw new DBUnexpectedError( $this, 'Error in BEGIN query: ' . $e->getMessage() );
+ if ( $this->trxMode ) {
+ $this->query( "BEGIN {$this->trxMode}", $fname );
+ } else {
+ $this->query( 'BEGIN', $fname );
}
$this->mTrxLevel = 1;
}
- protected function doCommit( $fname = '' ) {
- if ( $this->mTrxLevel == 0 ) {
- return;
- }
- try {
- $this->mConn->commit();
- } catch ( PDOException $e ) {
- throw new DBUnexpectedError( $this, 'Error in COMMIT query: ' . $e->getMessage() );
- }
- $this->mTrxLevel = 0;
- }
-
- protected function doRollback( $fname = '' ) {
- if ( $this->mTrxLevel == 0 ) {
- return;
- }
- $this->mConn->rollBack();
- $this->mTrxLevel = 0;
- }
-
/**
* @param string $s
* @return string
@@ -787,6 +802,10 @@ class DatabaseSqlite extends DatabaseBase {
// https://bugs.php.net/bug.php?id=63419
// There was already a similar report for SQLite3::escapeString, bug #62361:
// https://bugs.php.net/bug.php?id=62361
+ // There is an additional bug regarding sorting this data after insert
+ // on older versions of sqlite shipped with ubuntu 12.04
+ // https://bugzilla.wikimedia.org/show_bug.cgi?id=72367
+ wfDebugLog( __CLASS__, __FUNCTION__ . ': Quoting value containing null byte. For consistency all binary data should have been first processed with self::encodeBlob()' );
return "x'" . bin2hex( $s ) . "'";
} else {
return $this->mConn->quote( $s );
@@ -882,11 +901,9 @@ class DatabaseSqlite extends DatabaseBase {
}
public function lock( $lockName, $method, $timeout = 5 ) {
- global $wgSQLiteDataDir;
-
- if ( !is_dir( "$wgSQLiteDataDir/locks" ) ) { // create dir as needed
- if ( !is_writable( $wgSQLiteDataDir ) || !mkdir( "$wgSQLiteDataDir/locks" ) ) {
- throw new DBError( "Cannot create directory \"$wgSQLiteDataDir/locks\"." );
+ if ( !is_dir( "{$this->dbDir}/locks" ) ) { // create dir as needed
+ if ( !is_writable( $this->dbDir ) || !mkdir( "{$this->dbDir}/locks" ) ) {
+ throw new DBError( "Cannot create directory \"{$this->dbDir}/locks\"." );
}
}
@@ -981,18 +998,6 @@ class DatabaseSqlite extends DatabaseBase {
} // end DatabaseSqlite class
/**
- * This class allows simple acccess to a SQLite database independently from main database settings
- * @ingroup Database
- */
-class DatabaseSqliteStandalone extends DatabaseSqlite {
- public function __construct( $fileName, $flags = 0 ) {
- $this->mFlags = $flags;
- $this->tablePrefix( null );
- $this->openFile( $fileName );
- }
-}
-
-/**
* @ingroup Database
*/
class SQLiteField implements Field {