mirror of
https://github.com/dg/dibi.git
synced 2025-01-16 21:58:36 +01:00
Sqlite3Driver becomes alias for SqliteDriver
This commit is contained in:
parent
70b1e08d83
commit
3930dafe3f
@ -16,7 +16,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
|
||||
echo '<p>Connecting to Sqlite: ';
|
||||
try {
|
||||
dibi::connect([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
echo 'OK';
|
||||
@ -30,7 +30,7 @@ echo "</p>\n";
|
||||
echo '<p>Connecting to Sqlite: ';
|
||||
try {
|
||||
$connection = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
echo 'OK';
|
||||
|
@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -15,7 +15,7 @@ Tracy\Debugger::enable();
|
||||
<?php
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -15,7 +15,7 @@ date_default_timezone_set('Europe/Prague');
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -19,7 +19,7 @@ date_default_timezone_set('Europe/Prague');
|
||||
<?php
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -11,7 +11,7 @@ Tracy\Debugger::enable();
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -11,7 +11,7 @@ Tracy\Debugger::enable();
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -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'",
|
||||
|
@ -15,7 +15,7 @@ date_default_timezone_set('Europe/Prague');
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -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' => [
|
||||
|
@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -13,7 +13,7 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
|
||||
|
||||
|
||||
$dibi = new Dibi\Connection([
|
||||
'driver' => 'sqlite3',
|
||||
'driver' => 'sqlite',
|
||||
'database' => 'data/sample.s3db',
|
||||
]);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
301
src/Dibi/Drivers/SqliteDriver.php
Normal file
301
src/Dibi/Drivers/SqliteDriver.php
Normal file
@ -0,0 +1,301 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
|
||||
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dibi\Drivers;
|
||||
|
||||
use Dibi;
|
||||
use Dibi\Helpers;
|
||||
use SQLite3;
|
||||
|
||||
|
||||
/**
|
||||
* The driver for SQLite v3 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
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
123
src/Dibi/Drivers/SqliteResult.php
Normal file
123
src/Dibi/Drivers/SqliteResult.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
|
||||
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dibi\Drivers;
|
||||
|
||||
use Dibi;
|
||||
use Dibi\Helpers;
|
||||
|
||||
|
||||
/**
|
||||
* The driver for SQLite result set.
|
||||
*/
|
||||
class SqliteResult implements Dibi\ResultDriver
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
[sqlite] ; default
|
||||
driver = sqlite3
|
||||
driver = sqlite
|
||||
database = :memory:
|
||||
system = sqlite
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
[sqlite] ; default
|
||||
driver = sqlite3
|
||||
driver = sqlite
|
||||
database = :memory:
|
||||
system = sqlite
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
[sqlite] ; default
|
||||
driver = sqlite3
|
||||
driver = sqlite
|
||||
database = :memory:
|
||||
system = sqlite
|
||||
|
||||
|
@ -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'));
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user