* @file
* @ingroup Database
*/
+namespace Wikimedia\Rdbms;
+
+use PDO;
+use PDOException;
+use LockManager;
+use FSLockManager;
+use InvalidArgumentException;
+use RuntimeException;
+use stdClass;
/**
* @ingroup Database
*/
-class DatabaseSqlite extends DatabaseBase {
+class DatabaseSqlite extends Database {
/** @var bool Whether full text is enabled */
private static $fulltextEnabled = null;
/** @var string Directory */
protected $dbDir;
-
/** @var string File name for SQLite database file */
protected $dbPath;
-
/** @var string Transaction mode */
protected $trxMode;
/** @var int The number of rows affected as an integer */
protected $mAffectedRows;
-
/** @var resource */
protected $mLastResult;
/** @var FSLockManager (hopefully on the same server as the DB) */
protected $lockMgr;
+ /** @var array List of shared database already attached to this connection */
+ private $alreadyAttached = [];
+
/**
* Additional params include:
* - dbDirectory : directory containing the DB and the lock file directory
parent::__construct( $p );
// Super 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'] ) ) {
- $done = [];
- foreach ( $this->tableAliases as $params ) {
- if ( isset( $done[$params['dbname']] ) ) {
- continue;
- }
- $this->attachDatabase( $params['dbname'] );
- $done[$params['dbname']] = 1;
- }
- }
+ $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] );
}
}
$p['dbFilePath'] = $filename;
$p['schema'] = false;
$p['tablePrefix'] = '';
+ /** @var DatabaseSqlite $db */
+ $db = Database::factory( 'sqlite', $p );
- return DatabaseBase::factory( 'sqlite', $p );
+ return $db;
}
/**
* @param string $dbName
*
* @throws DBConnectionError
- * @return PDO
+ * @return bool
*/
function open( $server, $user, $pass, $dbName ) {
$this->close();
}
$this->openFile( $fileName );
- return $this->mConn;
+ return (bool)$this->mConn;
}
/**
$this->dbPath = $fileName;
try {
- if ( $this->mFlags & DBO_PERSISTENT ) {
+ if ( $this->mFlags & self::DBO_PERSISTENT ) {
$this->mConn = new PDO( "sqlite:$fileName", '', '',
[ PDO::ATTR_PERSISTENT => true ] );
} else {
return false;
}
+ public function selectDB( $db ) {
+ return false; // doesn't make sense
+ }
+
/**
* @return string SQLite DB file path
* @since 1.25
}
/**
- * Attaches external database to our connection, see http://sqlite.org/lang_attach.html
+ * Attaches external database to our connection, see https://sqlite.org/lang_attach.html
* for details.
*
* @param string $name Database name to be used in queries like
return parent::isWriteQuery( $sql ) && !preg_match( '/^(ATTACH|PRAGMA)\b/i', $sql );
}
+ protected function isTransactableQuery( $sql ) {
+ return parent::isTransactableQuery( $sql ) && !in_array(
+ $this->getQueryVerb( $sql ),
+ [ 'ATTACH', 'PRAGMA' ],
+ true
+ );
+ }
+
/**
* SQLite doesn't allow buffered results or data seeking etc, so we'll use fetchAll as the result
*
return str_replace( '"', '', parent::tableName( $name, $format ) );
}
- /**
- * Index names have DB scope
- *
- * @param string $index
- * @return string
- */
- protected function indexName( $index ) {
- return $index;
- }
-
/**
* This must be called after nextSequenceVal
*
/**
* @return int
*/
- function affectedRows() {
+ protected function fetchAffectedRowCount() {
return $this->mAffectedRows;
}
* @param string $table
* @param string $index
* @param string $fname
- * @return array
+ * @return array|false
*/
function indexInfo( $table, $index, $fname = __METHOD__ ) {
$sql = 'PRAGMA index_info(' . $this->addQuotes( $this->indexName( $index ) ) . ')';
$res = $this->query( $sql, $fname );
- if ( !$res ) {
- return null;
- }
- if ( $res->numRows() == 0 ) {
+ if ( !$res || $res->numRows() == 0 ) {
return false;
}
$info = [];
/**
* @param array $options
- * @return string
+ * @return array
*/
protected function makeUpdateOptionsArray( $options ) {
$options = parent::makeUpdateOptionsArray( $options );
}
/**
- * @param string $sqls
+ * @param string[] $sqls
* @param bool $all Whether to "UNION ALL" or not
* @return string
*/
return "x'" . bin2hex( $s->fetch() ) . "'";
} elseif ( is_bool( $s ) ) {
return (int)$s;
- } elseif ( strpos( $s, "\0" ) !== false ) {
+ } elseif ( strpos( (string)$s, "\0" ) !== false ) {
// SQLite doesn't support \0 in strings, so use the hex representation as a workaround.
// This is a known limitation of SQLite's mprintf function which PDO
// should work around, but doesn't. I have reported this to php.net as bug #63419:
'For consistency all binary data should have been ' .
'first processed with self::encodeBlob()'
);
- return "x'" . bin2hex( $s ) . "'";
+ return "x'" . bin2hex( (string)$s ) . "'";
} else {
- return $this->mConn->quote( $s );
- }
- }
-
- /**
- * @return string
- */
- function buildLike() {
- $params = func_get_args();
- if ( count( $params ) > 0 && is_array( $params[0] ) ) {
- $params = $params[0];
+ return $this->mConn->quote( (string)$s );
}
-
- return parent::buildLike( $params ) . "ESCAPE '\' ";
}
/**
return $this->query( $sql, $fName );
}
+ public function setTableAliases( array $aliases ) {
+ parent::setTableAliases( $aliases );
+ foreach ( $this->tableAliases as $params ) {
+ if ( isset( $this->alreadyAttached[$params['dbname']] ) ) {
+ continue;
+ }
+ $this->attachDatabase( $params['dbname'] );
+ $this->alreadyAttached[$params['dbname']] = true;
+ }
+ }
+
protected function requiresDatabaseUser() {
return false; // just a file
}
return 'SQLite ' . (string)$this->mConn->getAttribute( PDO::ATTR_SERVER_VERSION );
}
}
+
+class_alias( DatabaseSqlite::class, 'DatabaseSqlite' );