From 3930dafe3fce643140de944d4f0d7df227a21c8b Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 23 May 2018 17:08:25 +0200 Subject: [PATCH] Sqlite3Driver becomes alias for SqliteDriver --- examples/connecting-to-databases.php | 4 +- examples/database-reflection.php | 2 +- examples/dumping-sql-and-result-set.php | 2 +- examples/fetching-examples.php | 2 +- examples/importing-dump-from-file.php | 2 +- examples/query-language-and-conditions.php | 2 +- examples/query-language-basic-examples.php | 2 +- examples/result-set-data-types.php | 2 +- examples/tracy-and-exceptions.php | 2 +- examples/tracy.php | 2 +- examples/using-datetime.php | 2 +- examples/using-fluent-syntax.php | 2 +- examples/using-limit-and-offset.php | 2 +- examples/using-logger.php | 2 +- examples/using-substitutions.php | 2 +- examples/using-transactions.php | 2 +- src/Dibi/Drivers/PdoDriver.php | 2 +- src/Dibi/Drivers/Sqlite3Driver.php | 287 +------------------- src/Dibi/Drivers/Sqlite3Result.php | 109 +------- src/Dibi/Drivers/SqliteDriver.php | 301 +++++++++++++++++++++ src/Dibi/Drivers/SqliteResult.php | 123 +++++++++ tests/databases.appveyor.ini | 2 +- tests/databases.sample.ini | 2 +- tests/databases.travis.ini | 2 +- tests/dibi/Result.meta.phpt | 4 +- tests/dibi/bootstrap.php | 2 +- 26 files changed, 452 insertions(+), 416 deletions(-) create mode 100644 src/Dibi/Drivers/SqliteDriver.php create mode 100644 src/Dibi/Drivers/SqliteResult.php diff --git a/examples/connecting-to-databases.php b/examples/connecting-to-databases.php index c01ab7a..8e6c4b4 100644 --- a/examples/connecting-to-databases.php +++ b/examples/connecting-to-databases.php @@ -16,7 +16,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') { echo '

Connecting to Sqlite: '; try { dibi::connect([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); echo 'OK'; @@ -30,7 +30,7 @@ echo "

\n"; echo '

Connecting to Sqlite: '; try { $connection = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); echo 'OK'; diff --git a/examples/database-reflection.php b/examples/database-reflection.php index ea4c5be..252dc2d 100644 --- a/examples/database-reflection.php +++ b/examples/database-reflection.php @@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') { $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/dumping-sql-and-result-set.php b/examples/dumping-sql-and-result-set.php index 4fde36c..e04ce1d 100644 --- a/examples/dumping-sql-and-result-set.php +++ b/examples/dumping-sql-and-result-set.php @@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') { $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/fetching-examples.php b/examples/fetching-examples.php index b7278e7..0a91fa2 100644 --- a/examples/fetching-examples.php +++ b/examples/fetching-examples.php @@ -15,7 +15,7 @@ Tracy\Debugger::enable(); 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/importing-dump-from-file.php b/examples/importing-dump-from-file.php index b538fd3..655451e 100644 --- a/examples/importing-dump-from-file.php +++ b/examples/importing-dump-from-file.php @@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') { $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/query-language-and-conditions.php b/examples/query-language-and-conditions.php index d4a0ad7..4f53b2b 100644 --- a/examples/query-language-and-conditions.php +++ b/examples/query-language-and-conditions.php @@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') { $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/query-language-basic-examples.php b/examples/query-language-basic-examples.php index 69a9abb..b0efe52 100644 --- a/examples/query-language-basic-examples.php +++ b/examples/query-language-basic-examples.php @@ -15,7 +15,7 @@ date_default_timezone_set('Europe/Prague'); $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/result-set-data-types.php b/examples/result-set-data-types.php index 764eec7..fdb83f8 100644 --- a/examples/result-set-data-types.php +++ b/examples/result-set-data-types.php @@ -19,7 +19,7 @@ date_default_timezone_set('Europe/Prague'); 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/tracy-and-exceptions.php b/examples/tracy-and-exceptions.php index afb43c1..bb3faa2 100644 --- a/examples/tracy-and-exceptions.php +++ b/examples/tracy-and-exceptions.php @@ -11,7 +11,7 @@ Tracy\Debugger::enable(); $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/tracy.php b/examples/tracy.php index bff98b8..d2a4eac 100644 --- a/examples/tracy.php +++ b/examples/tracy.php @@ -11,7 +11,7 @@ Tracy\Debugger::enable(); $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/using-datetime.php b/examples/using-datetime.php index 91d2d8a..272a0ae 100644 --- a/examples/using-datetime.php +++ b/examples/using-datetime.php @@ -16,7 +16,7 @@ date_default_timezone_set('Europe/Prague'); // CHANGE TO REAL PARAMETERS! $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', 'formatDate' => "'Y-m-d'", 'formatDateTime' => "'Y-m-d H-i-s'", diff --git a/examples/using-fluent-syntax.php b/examples/using-fluent-syntax.php index 142aac9..f005a32 100644 --- a/examples/using-fluent-syntax.php +++ b/examples/using-fluent-syntax.php @@ -15,7 +15,7 @@ date_default_timezone_set('Europe/Prague'); $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/using-limit-and-offset.php b/examples/using-limit-and-offset.php index 7b70c28..cbdeb9b 100644 --- a/examples/using-limit-and-offset.php +++ b/examples/using-limit-and-offset.php @@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') { $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/using-logger.php b/examples/using-logger.php index cbfa0bf..1849331 100644 --- a/examples/using-logger.php +++ b/examples/using-logger.php @@ -15,7 +15,7 @@ date_default_timezone_set('Europe/Prague'); $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', // enable query logging to this file 'profiler' => [ diff --git a/examples/using-substitutions.php b/examples/using-substitutions.php index a2279f7..d4d066d 100644 --- a/examples/using-substitutions.php +++ b/examples/using-substitutions.php @@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') { $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/examples/using-transactions.php b/examples/using-transactions.php index 74331ca..17718f4 100644 --- a/examples/using-transactions.php +++ b/examples/using-transactions.php @@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') { $dibi = new Dibi\Connection([ - 'driver' => 'sqlite3', + 'driver' => 'sqlite', 'database' => 'data/sample.s3db', ]); diff --git a/src/Dibi/Drivers/PdoDriver.php b/src/Dibi/Drivers/PdoDriver.php index abddab4..e8ea652 100644 --- a/src/Dibi/Drivers/PdoDriver.php +++ b/src/Dibi/Drivers/PdoDriver.php @@ -110,7 +110,7 @@ class PdoDriver implements Dibi\Driver throw PostgreDriver::createException($message, $sqlState, $sql); case 'sqlite': - throw Sqlite3Driver::createException($message, $code, $sql); + throw SqliteDriver::createException($message, $code, $sql); default: throw new Dibi\DriverException($message, $code, $sql); diff --git a/src/Dibi/Drivers/Sqlite3Driver.php b/src/Dibi/Drivers/Sqlite3Driver.php index fdabcfd..f3dfa9e 100644 --- a/src/Dibi/Drivers/Sqlite3Driver.php +++ b/src/Dibi/Drivers/Sqlite3Driver.php @@ -9,293 +9,10 @@ declare(strict_types=1); namespace Dibi\Drivers; -use Dibi; -use Dibi\Helpers; -use SQLite3; - /** - * The driver for SQLite3 database. - * - * Driver options: - * - database (or file) => the filename of the SQLite3 database - * - formatDate => how to format date in SQL (@see date) - * - formatDateTime => how to format datetime in SQL (@see date) - * - resource (SQLite3) => existing connection resource + * Alias for SqliteDriver driver. */ -class Sqlite3Driver implements Dibi\Driver +class Sqlite3Driver extends SqliteDriver { - use Dibi\Strict; - - /** @var SQLite3 */ - private $connection; - - /** @var string Date format */ - private $fmtDate; - - /** @var string Datetime format */ - private $fmtDateTime; - - - /** - * @throws Dibi\NotSupportedException - */ - public function __construct(array &$config) - { - if (!extension_loaded('sqlite3')) { - throw new Dibi\NotSupportedException("PHP extension 'sqlite3' is not loaded."); - } - - if (isset($config['dbcharset']) || isset($config['charset'])) { - throw new Dibi\NotSupportedException('Options dbcharset and charset are not longer supported.'); - } - - Helpers::alias($config, 'database', 'file'); - $this->fmtDate = $config['formatDate'] ?? 'U'; - $this->fmtDateTime = $config['formatDateTime'] ?? 'U'; - - if (isset($config['resource']) && $config['resource'] instanceof SQLite3) { - $this->connection = $config['resource']; - } else { - try { - $this->connection = new SQLite3($config['database']); - } catch (\Exception $e) { - throw new Dibi\DriverException($e->getMessage(), $e->getCode()); - } - } - - // enable foreign keys support (defaultly disabled; if disabled then foreign key constraints are not enforced) - $version = SQLite3::version(); - if ($version['versionNumber'] >= '3006019') { - $this->query('PRAGMA foreign_keys = ON'); - } - } - - - /** - * Disconnects from a database. - */ - public function disconnect(): void - { - $this->connection->close(); - } - - - /** - * Executes the SQL query. - * @throws Dibi\DriverException - */ - public function query(string $sql): ?Dibi\ResultDriver - { - $res = @$this->connection->query($sql); // intentionally @ - if ($code = $this->connection->lastErrorCode()) { - throw static::createException($this->connection->lastErrorMsg(), $code, $sql); - - } elseif ($res instanceof \SQLite3Result && $res->numColumns()) { - return $this->createResultDriver($res); - } - return null; - } - - - public static function createException(string $message, $code, string $sql): Dibi\DriverException - { - if ($code !== 19) { - return new Dibi\DriverException($message, $code, $sql); - - } elseif (strpos($message, 'must be unique') !== false - || strpos($message, 'is not unique') !== false - || strpos($message, 'UNIQUE constraint failed') !== false - ) { - return new Dibi\UniqueConstraintViolationException($message, $code, $sql); - - } elseif (strpos($message, 'may not be null') !== false - || strpos($message, 'NOT NULL constraint failed') !== false - ) { - return new Dibi\NotNullConstraintViolationException($message, $code, $sql); - - } elseif (strpos($message, 'foreign key constraint failed') !== false - || strpos($message, 'FOREIGN KEY constraint failed') !== false - ) { - return new Dibi\ForeignKeyConstraintViolationException($message, $code, $sql); - - } else { - return new Dibi\ConstraintViolationException($message, $code, $sql); - } - } - - - /** - * Gets the number of affected rows by the last INSERT, UPDATE or DELETE query. - */ - public function getAffectedRows(): ?int - { - return $this->connection->changes(); - } - - - /** - * Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query. - */ - public function getInsertId(?string $sequence): ?int - { - return $this->connection->lastInsertRowID(); - } - - - /** - * Begins a transaction (if supported). - * @throws Dibi\DriverException - */ - public function begin(string $savepoint = null): void - { - $this->query($savepoint ? "SAVEPOINT $savepoint" : 'BEGIN'); - } - - - /** - * Commits statements in a transaction. - * @throws Dibi\DriverException - */ - public function commit(string $savepoint = null): void - { - $this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT'); - } - - - /** - * Rollback changes in a transaction. - * @throws Dibi\DriverException - */ - public function rollback(string $savepoint = null): void - { - $this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK'); - } - - - /** - * Returns the connection resource. - */ - public function getResource(): ?SQLite3 - { - return $this->connection; - } - - - /** - * Returns the connection reflector. - */ - public function getReflector(): Dibi\Reflector - { - return new SqliteReflector($this); - } - - - /** - * Result set driver factory. - */ - public function createResultDriver(\SQLite3Result $result): Sqlite3Result - { - return new Sqlite3Result($result); - } - - - /********************* SQL ****************d*g**/ - - - /** - * Encodes data for use in a SQL statement. - */ - public function escapeText(string $value): string - { - return "'" . $this->connection->escapeString($value) . "'"; - } - - - public function escapeBinary(string $value): string - { - return "X'" . bin2hex($value) . "'"; - } - - - public function escapeIdentifier(string $value): string - { - return '[' . strtr($value, '[]', ' ') . ']'; - } - - - public function escapeBool(bool $value): string - { - return $value ? '1' : '0'; - } - - - /** - * @param \DateTimeInterface|string|int $value - */ - public function escapeDate($value): string - { - if (!$value instanceof \DateTimeInterface) { - $value = new Dibi\DateTime($value); - } - return $value->format($this->fmtDate); - } - - - /** - * @param \DateTimeInterface|string|int $value - */ - public function escapeDateTime($value): string - { - if (!$value instanceof \DateTimeInterface) { - $value = new Dibi\DateTime($value); - } - return $value->format($this->fmtDateTime); - } - - - /** - * Encodes string for use in a LIKE statement. - */ - public function escapeLike(string $value, int $pos): string - { - $value = addcslashes($this->connection->escapeString($value), '%_\\'); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'"; - } - - - /** - * Injects LIMIT/OFFSET to the SQL query. - */ - public function applyLimit(string &$sql, ?int $limit, ?int $offset): void - { - if ($limit < 0 || $offset < 0) { - throw new Dibi\NotSupportedException('Negative offset or limit.'); - - } elseif ($limit !== null || $offset) { - $sql .= ' LIMIT ' . ($limit === null ? '-1' : $limit) - . ($offset ? ' OFFSET ' . $offset : ''); - } - } - - - /********************* user defined functions ****************d*g**/ - - - /** - * Registers an user defined function for use in SQL statements. - */ - public function registerFunction(string $name, callable $callback, int $numArgs = -1): void - { - $this->connection->createFunction($name, $callback, $numArgs); - } - - - /** - * Registers an aggregating user defined function for use in SQL statements. - */ - public function registerAggregateFunction(string $name, callable $rowCallback, callable $agrCallback, int $numArgs = -1): void - { - $this->connection->createAggregate($name, $rowCallback, $agrCallback, $numArgs); - } } diff --git a/src/Dibi/Drivers/Sqlite3Result.php b/src/Dibi/Drivers/Sqlite3Result.php index 220cf00..26cca51 100644 --- a/src/Dibi/Drivers/Sqlite3Result.php +++ b/src/Dibi/Drivers/Sqlite3Result.php @@ -9,115 +9,10 @@ declare(strict_types=1); namespace Dibi\Drivers; -use Dibi; -use Dibi\Helpers; - /** - * The driver for SQLite3 result set. + * Alias for SqliteResult driver. */ -class Sqlite3Result implements Dibi\ResultDriver +class Sqlite3Result extends SqliteResult { - use Dibi\Strict; - - /** @var \SQLite3Result */ - private $resultSet; - - /** @var bool */ - private $autoFree = true; - - - public function __construct(\SQLite3Result $resultSet) - { - $this->resultSet = $resultSet; - } - - - /** - * Automatically frees the resources allocated for this result set. - */ - public function __destruct() - { - if ($this->autoFree && $this->getResultResource()) { - @$this->free(); - } - } - - - /** - * Returns the number of rows in a result set. - * @throws Dibi\NotSupportedException - */ - public function getRowCount(): int - { - throw new Dibi\NotSupportedException('Row count is not available for unbuffered queries.'); - } - - - /** - * Fetches the row at current position and moves the internal cursor to the next position. - * @param bool $assoc true for associative array, false for numeric - */ - public function fetch(bool $assoc): ?array - { - return Helpers::false2Null($this->resultSet->fetchArray($assoc ? SQLITE3_ASSOC : SQLITE3_NUM)); - } - - - /** - * Moves cursor position without fetching row. - * @throws Dibi\NotSupportedException - */ - public function seek(int $row): bool - { - throw new Dibi\NotSupportedException('Cannot seek an unbuffered result set.'); - } - - - /** - * Frees the resources allocated for this result set. - */ - public function free(): void - { - $this->resultSet->finalize(); - } - - - /** - * Returns metadata for all columns in a result set. - */ - public function getResultColumns(): array - { - $count = $this->resultSet->numColumns(); - $columns = []; - static $types = [SQLITE3_INTEGER => 'int', SQLITE3_FLOAT => 'float', SQLITE3_TEXT => 'text', SQLITE3_BLOB => 'blob', SQLITE3_NULL => 'null']; - for ($i = 0; $i < $count; $i++) { - $columns[] = [ - 'name' => $this->resultSet->columnName($i), - 'table' => null, - 'fullname' => $this->resultSet->columnName($i), - 'nativetype' => $types[$this->resultSet->columnType($i)], - ]; - } - return $columns; - } - - - /** - * Returns the result set resource. - */ - public function getResultResource(): \SQLite3Result - { - $this->autoFree = false; - return $this->resultSet; - } - - - /** - * Decodes data from result set. - */ - public function unescapeBinary(string $value): string - { - return $value; - } } diff --git a/src/Dibi/Drivers/SqliteDriver.php b/src/Dibi/Drivers/SqliteDriver.php new file mode 100644 index 0000000..2ea27a0 --- /dev/null +++ b/src/Dibi/Drivers/SqliteDriver.php @@ -0,0 +1,301 @@ + the filename of the SQLite3 database + * - formatDate => how to format date in SQL (@see date) + * - formatDateTime => how to format datetime in SQL (@see date) + * - resource (SQLite3) => existing connection resource + */ +class SqliteDriver implements Dibi\Driver +{ + use Dibi\Strict; + + /** @var SQLite3 */ + private $connection; + + /** @var string Date format */ + private $fmtDate; + + /** @var string Datetime format */ + private $fmtDateTime; + + + /** + * @throws Dibi\NotSupportedException + */ + public function __construct(array &$config) + { + if (!extension_loaded('sqlite3')) { + throw new Dibi\NotSupportedException("PHP extension 'sqlite3' is not loaded."); + } + + if (isset($config['dbcharset']) || isset($config['charset'])) { + throw new Dibi\NotSupportedException('Options dbcharset and charset are not longer supported.'); + } + + Helpers::alias($config, 'database', 'file'); + $this->fmtDate = $config['formatDate'] ?? 'U'; + $this->fmtDateTime = $config['formatDateTime'] ?? 'U'; + + if (isset($config['resource']) && $config['resource'] instanceof SQLite3) { + $this->connection = $config['resource']; + } else { + try { + $this->connection = new SQLite3($config['database']); + } catch (\Exception $e) { + throw new Dibi\DriverException($e->getMessage(), $e->getCode()); + } + } + + // enable foreign keys support (defaultly disabled; if disabled then foreign key constraints are not enforced) + $version = SQLite3::version(); + if ($version['versionNumber'] >= '3006019') { + $this->query('PRAGMA foreign_keys = ON'); + } + } + + + /** + * Disconnects from a database. + */ + public function disconnect(): void + { + $this->connection->close(); + } + + + /** + * Executes the SQL query. + * @throws Dibi\DriverException + */ + public function query(string $sql): ?Dibi\ResultDriver + { + $res = @$this->connection->query($sql); // intentionally @ + if ($code = $this->connection->lastErrorCode()) { + throw static::createException($this->connection->lastErrorMsg(), $code, $sql); + + } elseif ($res instanceof \SQLite3Result && $res->numColumns()) { + return $this->createResultDriver($res); + } + return null; + } + + + public static function createException(string $message, $code, string $sql): Dibi\DriverException + { + if ($code !== 19) { + return new Dibi\DriverException($message, $code, $sql); + + } elseif (strpos($message, 'must be unique') !== false + || strpos($message, 'is not unique') !== false + || strpos($message, 'UNIQUE constraint failed') !== false + ) { + return new Dibi\UniqueConstraintViolationException($message, $code, $sql); + + } elseif (strpos($message, 'may not be null') !== false + || strpos($message, 'NOT NULL constraint failed') !== false + ) { + return new Dibi\NotNullConstraintViolationException($message, $code, $sql); + + } elseif (strpos($message, 'foreign key constraint failed') !== false + || strpos($message, 'FOREIGN KEY constraint failed') !== false + ) { + return new Dibi\ForeignKeyConstraintViolationException($message, $code, $sql); + + } else { + return new Dibi\ConstraintViolationException($message, $code, $sql); + } + } + + + /** + * Gets the number of affected rows by the last INSERT, UPDATE or DELETE query. + */ + public function getAffectedRows(): ?int + { + return $this->connection->changes(); + } + + + /** + * Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query. + */ + public function getInsertId(?string $sequence): ?int + { + return $this->connection->lastInsertRowID(); + } + + + /** + * Begins a transaction (if supported). + * @throws Dibi\DriverException + */ + public function begin(string $savepoint = null): void + { + $this->query($savepoint ? "SAVEPOINT $savepoint" : 'BEGIN'); + } + + + /** + * Commits statements in a transaction. + * @throws Dibi\DriverException + */ + public function commit(string $savepoint = null): void + { + $this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT'); + } + + + /** + * Rollback changes in a transaction. + * @throws Dibi\DriverException + */ + public function rollback(string $savepoint = null): void + { + $this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK'); + } + + + /** + * Returns the connection resource. + */ + public function getResource(): ?SQLite3 + { + return $this->connection; + } + + + /** + * Returns the connection reflector. + */ + public function getReflector(): Dibi\Reflector + { + return new SqliteReflector($this); + } + + + /** + * Result set driver factory. + */ + public function createResultDriver(\SQLite3Result $result): SqliteResult + { + return new SqliteResult($result); + } + + + /********************* SQL ****************d*g**/ + + + /** + * Encodes data for use in a SQL statement. + */ + public function escapeText(string $value): string + { + return "'" . $this->connection->escapeString($value) . "'"; + } + + + public function escapeBinary(string $value): string + { + return "X'" . bin2hex($value) . "'"; + } + + + public function escapeIdentifier(string $value): string + { + return '[' . strtr($value, '[]', ' ') . ']'; + } + + + public function escapeBool(bool $value): string + { + return $value ? '1' : '0'; + } + + + /** + * @param \DateTimeInterface|string|int $value + */ + public function escapeDate($value): string + { + if (!$value instanceof \DateTimeInterface) { + $value = new Dibi\DateTime($value); + } + return $value->format($this->fmtDate); + } + + + /** + * @param \DateTimeInterface|string|int $value + */ + public function escapeDateTime($value): string + { + if (!$value instanceof \DateTimeInterface) { + $value = new Dibi\DateTime($value); + } + return $value->format($this->fmtDateTime); + } + + + /** + * Encodes string for use in a LIKE statement. + */ + public function escapeLike(string $value, int $pos): string + { + $value = addcslashes($this->connection->escapeString($value), '%_\\'); + return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'"; + } + + + /** + * Injects LIMIT/OFFSET to the SQL query. + */ + public function applyLimit(string &$sql, ?int $limit, ?int $offset): void + { + if ($limit < 0 || $offset < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); + + } elseif ($limit !== null || $offset) { + $sql .= ' LIMIT ' . ($limit === null ? '-1' : $limit) + . ($offset ? ' OFFSET ' . $offset : ''); + } + } + + + /********************* user defined functions ****************d*g**/ + + + /** + * Registers an user defined function for use in SQL statements. + */ + public function registerFunction(string $name, callable $callback, int $numArgs = -1): void + { + $this->connection->createFunction($name, $callback, $numArgs); + } + + + /** + * Registers an aggregating user defined function for use in SQL statements. + */ + public function registerAggregateFunction(string $name, callable $rowCallback, callable $agrCallback, int $numArgs = -1): void + { + $this->connection->createAggregate($name, $rowCallback, $agrCallback, $numArgs); + } +} diff --git a/src/Dibi/Drivers/SqliteResult.php b/src/Dibi/Drivers/SqliteResult.php new file mode 100644 index 0000000..3d28882 --- /dev/null +++ b/src/Dibi/Drivers/SqliteResult.php @@ -0,0 +1,123 @@ +resultSet = $resultSet; + } + + + /** + * Automatically frees the resources allocated for this result set. + */ + public function __destruct() + { + if ($this->autoFree && $this->getResultResource()) { + @$this->free(); + } + } + + + /** + * Returns the number of rows in a result set. + * @throws Dibi\NotSupportedException + */ + public function getRowCount(): int + { + throw new Dibi\NotSupportedException('Row count is not available for unbuffered queries.'); + } + + + /** + * Fetches the row at current position and moves the internal cursor to the next position. + * @param bool $assoc true for associative array, false for numeric + */ + public function fetch(bool $assoc): ?array + { + return Helpers::false2Null($this->resultSet->fetchArray($assoc ? SQLITE3_ASSOC : SQLITE3_NUM)); + } + + + /** + * Moves cursor position without fetching row. + * @throws Dibi\NotSupportedException + */ + public function seek(int $row): bool + { + throw new Dibi\NotSupportedException('Cannot seek an unbuffered result set.'); + } + + + /** + * Frees the resources allocated for this result set. + */ + public function free(): void + { + $this->resultSet->finalize(); + } + + + /** + * Returns metadata for all columns in a result set. + */ + public function getResultColumns(): array + { + $count = $this->resultSet->numColumns(); + $columns = []; + static $types = [SQLITE3_INTEGER => 'int', SQLITE3_FLOAT => 'float', SQLITE3_TEXT => 'text', SQLITE3_BLOB => 'blob', SQLITE3_NULL => 'null']; + for ($i = 0; $i < $count; $i++) { + $columns[] = [ + 'name' => $this->resultSet->columnName($i), + 'table' => null, + 'fullname' => $this->resultSet->columnName($i), + 'nativetype' => $types[$this->resultSet->columnType($i)], + ]; + } + return $columns; + } + + + /** + * Returns the result set resource. + */ + public function getResultResource(): \SQLite3Result + { + $this->autoFree = false; + return $this->resultSet; + } + + + /** + * Decodes data from result set. + */ + public function unescapeBinary(string $value): string + { + return $value; + } +} diff --git a/tests/databases.appveyor.ini b/tests/databases.appveyor.ini index 80cfa15..0e8c924 100644 --- a/tests/databases.appveyor.ini +++ b/tests/databases.appveyor.ini @@ -1,5 +1,5 @@ [sqlite] ; default -driver = sqlite3 +driver = sqlite database = :memory: system = sqlite diff --git a/tests/databases.sample.ini b/tests/databases.sample.ini index 07a9d21..4b747b6 100644 --- a/tests/databases.sample.ini +++ b/tests/databases.sample.ini @@ -1,5 +1,5 @@ [sqlite] ; default -driver = sqlite3 +driver = sqlite database = :memory: system = sqlite diff --git a/tests/databases.travis.ini b/tests/databases.travis.ini index f7f14ee..3160cbe 100644 --- a/tests/databases.travis.ini +++ b/tests/databases.travis.ini @@ -1,5 +1,5 @@ [sqlite] ; default -driver = sqlite3 +driver = sqlite database = :memory: system = sqlite diff --git a/tests/dibi/Result.meta.phpt b/tests/dibi/Result.meta.phpt index aa821a3..1826931 100644 --- a/tests/dibi/Result.meta.phpt +++ b/tests/dibi/Result.meta.phpt @@ -32,7 +32,7 @@ Assert::same( ); -if (!in_array($config['driver'], ['sqlite3', 'pdo', 'sqlsrv'], true)) { +if (!in_array($config['driver'], ['sqlite', 'pdo', 'sqlsrv'], true)) { Assert::same( ['products.product_id', 'orders.order_id', 'customers.name', 'xXx'], $info->getColumnNames(true) @@ -43,7 +43,7 @@ if (!in_array($config['driver'], ['sqlite3', 'pdo', 'sqlsrv'], true)) { $columns = $info->getColumns(); Assert::same('product_id', $columns[0]->getName()); -if (!in_array($config['driver'], ['sqlite3', 'pdo', 'sqlsrv'], true)) { +if (!in_array($config['driver'], ['sqlite', 'pdo', 'sqlsrv'], true)) { Assert::same('products', $columns[0]->getTableName()); } Assert::null($columns[0]->getVendorInfo('xxx')); diff --git a/tests/dibi/bootstrap.php b/tests/dibi/bootstrap.php index 5740c0a..a26588d 100644 --- a/tests/dibi/bootstrap.php +++ b/tests/dibi/bootstrap.php @@ -68,7 +68,7 @@ function reformat($s) function num($n) { global $config; - if (substr($config['dsn'] ?? '', 0, 5) === 'odbc:' || $config['driver'] === 'sqlite') { + if (substr($config['dsn'] ?? '', 0, 5) === 'odbc:') { $n = is_float($n) ? "$n.0" : (string) $n; } return $n;