X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Flibs%2Frdbms%2Fdatabase%2FDatabaseSqlite.php;h=f282b17a0f8a1346618408c1af4c0705f9d4d737;hp=3d6cee350fb92c27cbd160fcdeb98bec271c3b11;hb=0d57b370dfe726af5f3ecf210f9f352ad9e26f0f;hpb=ca8cd77115d4369a3d08554e152acd08a83e964a diff --git a/includes/libs/rdbms/database/DatabaseSqlite.php b/includes/libs/rdbms/database/DatabaseSqlite.php index 3d6cee350f..f282b17a0f 100644 --- a/includes/libs/rdbms/database/DatabaseSqlite.php +++ b/includes/libs/rdbms/database/DatabaseSqlite.php @@ -69,24 +69,13 @@ class DatabaseSqlite extends Database { */ function __construct( array $p ) { if ( isset( $p['dbFilePath'] ) ) { - parent::__construct( $p ); - // Standalone .sqlite file mode. - // Super doesn't open when $user is false, but we can work with $dbName, - // which is derived from the file path in this case. - $this->openFile( $p['dbFilePath'] ); - $lockDomain = md5( $p['dbFilePath'] ); - } elseif ( !isset( $p['dbDirectory'] ) ) { - throw new InvalidArgumentException( "Need 'dbDirectory' or 'dbFilePath' parameter." ); - } else { + $this->dbPath = $p['dbFilePath']; + $lockDomain = md5( $this->dbPath ); + } elseif ( isset( $p['dbDirectory'] ) ) { $this->dbDir = $p['dbDirectory']; - $this->dbName = $p['dbname']; - $lockDomain = $this->dbName; - // Stock wiki mode using standard file names per DB. - parent::__construct( $p ); - // Super doesn't open when $user is false, but we can work with $dbName - if ( $p['dbname'] && !$this->isOpen() ) { - $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] ); - } + $lockDomain = $p['dbname']; + } else { + throw new InvalidArgumentException( "Need 'dbDirectory' or 'dbFilePath' parameter." ); } $this->trxMode = isset( $p['trxMode'] ) ? strtoupper( $p['trxMode'] ) : null; @@ -101,6 +90,8 @@ class DatabaseSqlite extends Database { 'domain' => $lockDomain, 'lockDirectory' => "{$this->dbDir}/locks" ] ); + + parent::__construct( $p ); } protected static function getAttributes() { @@ -126,6 +117,28 @@ class DatabaseSqlite extends Database { return $db; } + protected function doInitConnection() { + if ( $this->dbPath !== null ) { + // Standalone .sqlite file mode. + $this->openFile( $this->dbPath, $this->connectionParams['dbname'] ); + } elseif ( $this->dbDir !== null ) { + // Stock wiki mode using standard file names per DB + if ( strlen( $this->connectionParams['dbname'] ) ) { + $this->open( + $this->connectionParams['host'], + $this->connectionParams['user'], + $this->connectionParams['password'], + $this->connectionParams['dbname'] + ); + } else { + // Caller will manually call open() later? + $this->connLogger->debug( __METHOD__ . ': no database opened.' ); + } + } else { + throw new InvalidArgumentException( "Need 'dbDirectory' or 'dbFilePath' parameter." ); + } + } + /** * @return string */ @@ -146,7 +159,7 @@ class DatabaseSqlite extends Database { * NOTE: only $dbName is used, the other parameters are irrelevant for SQLite databases * * @param string $server - * @param string $user + * @param string $user Unused * @param string $pass * @param string $dbName * @@ -160,7 +173,7 @@ class DatabaseSqlite extends Database { $this->conn = false; throw new DBConnectionError( $this, "SQLite database not accessible" ); } - $this->openFile( $fileName ); + $this->openFile( $fileName, $dbName ); return (bool)$this->conn; } @@ -169,10 +182,11 @@ class DatabaseSqlite extends Database { * Opens a database file * * @param string $fileName + * @param string $dbName * @throws DBConnectionError * @return PDO|bool SQL connection or false if failed */ - protected function openFile( $fileName ) { + protected function openFile( $fileName, $dbName ) { $err = false; $this->dbPath = $fileName; @@ -192,8 +206,9 @@ class DatabaseSqlite extends Database { throw new DBConnectionError( $this, $err ); } - $this->opened = !!$this->conn; + $this->opened = is_object( $this->conn ); if ( $this->opened ) { + $this->dbName = $dbName; # Set error codes only, don't raise exceptions $this->conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT ); # Enforce LIKE to be case sensitive, just like MySQL @@ -205,10 +220,6 @@ class DatabaseSqlite extends Database { return false; } - public function selectDB( $db ) { - return false; // doesn't make sense - } - /** * @return string SQLite DB file path * @since 1.25 @@ -315,7 +326,7 @@ class DatabaseSqlite extends Database { * @return bool|ResultWrapper */ protected function doQuery( $sql ) { - $res = $this->conn->query( $sql ); + $res = $this->getBindingHandle()->query( $sql ); if ( $res === false ) { return false; } @@ -451,7 +462,7 @@ class DatabaseSqlite extends Database { */ function insertId() { // PDO::lastInsertId yields a string :( - return intval( $this->conn->lastInsertId() ); + return intval( $this->getBindingHandle()->lastInsertId() ); } /** @@ -699,13 +710,6 @@ class DatabaseSqlite extends Database { return $this->lastErrno() == 5; // SQLITE_BUSY } - /** - * @return bool - */ - function wasErrorReissuable() { - return $this->lastErrno() == 17; // SQLITE_SCHEMA; - } - /** * @return bool */ @@ -713,6 +717,18 @@ class DatabaseSqlite extends Database { return $this->lastErrno() == 8; // SQLITE_READONLY; } + public function wasConnectionError( $errno ) { + return $errno == 17; // SQLITE_SCHEMA; + } + + protected function wasKnownStatementRollbackError() { + // ON CONFLICT ROLLBACK clauses make it so that SQLITE_CONSTRAINT error is + // ambiguous with regard to whether it implies a ROLLBACK or an ABORT happened. + // https://sqlite.org/lang_createtable.html#uniqueconst + // https://sqlite.org/lang_conflict.html + return false; + } + /** * @return string Wikitext of a link to the server software's web site */ @@ -724,7 +740,7 @@ class DatabaseSqlite extends Database { * @return string Version information from the database */ function getServerVersion() { - $ver = $this->conn->getAttribute( PDO::ATTR_SERVER_VERSION ); + $ver = $this->getBindingHandle()->getAttribute( PDO::ATTR_SERVER_VERSION ); return $ver; } @@ -814,10 +830,19 @@ class DatabaseSqlite extends Database { ); return "x'" . bin2hex( (string)$s ) . "'"; } else { - return $this->conn->quote( (string)$s ); + return $this->getBindingHandle()->quote( (string)$s ); } } + public function buildSubstring( $input, $startPosition, $length = null ) { + $this->assertBuildSubstringParams( $startPosition, $length ); + $params = [ $input, $startPosition ]; + if ( $length !== null ) { + $params[] = $length; + } + return 'SUBSTR(' . implode( ',', $params ) . ')'; + } + /** * @param string $field Field or column to cast * @return string @@ -1050,15 +1075,30 @@ class DatabaseSqlite extends Database { } } - protected function requiresDatabaseUser() { - return false; // just a file + public function resetSequenceForTable( $table, $fname = __METHOD__ ) { + $encTable = $this->addIdentifierQuotes( 'sqlite_sequence' ); + $encName = $this->addQuotes( $this->tableName( $table, 'raw' ) ); + $this->query( "DELETE FROM $encTable WHERE name = $encName", $fname ); + } + + public function databasesAreIndependent() { + return true; } /** * @return string */ public function __toString() { - return 'SQLite ' . (string)$this->conn->getAttribute( PDO::ATTR_SERVER_VERSION ); + return is_object( $this->conn ) + ? 'SQLite ' . (string)$this->conn->getAttribute( PDO::ATTR_SERVER_VERSION ) + : '(not connected)'; + } + + /** + * @return PDO + */ + protected function getBindingHandle() { + return parent::getBindingHandle(); } }