refactor MySQL component to support SQLite at the same time

This commit is contained in:
crazywhalecc
2022-08-27 19:45:23 +08:00
parent e9b6965678
commit 085472a12c
8 changed files with 199 additions and 160 deletions

View File

@@ -0,0 +1,131 @@
<?php
/** @noinspection PhpComposerExtensionStubsInspection */
declare(strict_types=1);
namespace ZM\Store\Database;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\ParameterType;
use PDO;
use PDOException;
class DBConnection implements Connection
{
/** @var PDO */
private $conn;
private $pool_name;
public function __construct($params)
{
logger()->debug('Constructing...');
$this->conn = DBPool::pool($params['dbName'])->get();
$this->pool_name = $params['dbName'];
}
public function __destruct()
{
logger()->debug('Destructing');
DBPool::pool($this->pool_name)->put($this->conn);
}
/**
* @param mixed $sql
* @param mixed $options
* @throws DBException
*/
public function prepare($sql, $options = [])
{
try {
logger()->debug('Running SQL prepare: ' . $sql);
$statement = $this->conn->prepare($sql, $options);
assert($statement !== false);
} catch (PDOException $exception) {
throw new DBException($exception->getMessage(), 0, $exception);
}
return new DBStatement($statement);
}
/**
* @throws DBException
*/
public function query(...$args)
{
try {
$statement = $this->conn->query(...$args);
assert($statement !== false);
} catch (PDOException $exception) {
throw new DBException($exception->getMessage(), 0, $exception);
}
return new DBStatement($statement);
}
public function quote($value, $type = ParameterType::STRING)
{
return $this->conn->quote($value, $type);
}
/**
* @param mixed $sql
* @throws DBException
*/
public function exec($sql)
{
try {
logger()->debug('Running SQL exec: ' . $sql);
$statement = $this->conn->exec($sql);
assert($statement !== false);
return $statement;
} catch (PDOException $exception) {
throw new DBException($exception->getMessage(), 0, $exception);
}
}
/**
* @param null|mixed $name
* @throws DBException
*/
public function lastInsertId($name = null)
{
try {
return $name === null ? $this->conn->lastInsertId() : $this->conn->lastInsertId($name);
} catch (PDOException $exception) {
throw new DBException($exception->getMessage(), 0, $exception);
}
}
public function beginTransaction()
{
return $this->conn->beginTransaction();
}
public function commit()
{
return $this->conn->commit();
}
public function rollBack()
{
return $this->conn->rollBack();
}
public function errorCode()
{
return $this->conn->errorCode();
}
public function errorInfo()
{
return $this->conn->errorInfo();
}
/**
* @return mixed
*/
public function getPoolName()
{
return $this->pool_name;
}
}

View File

@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace ZM\Store\Database;
use ZM\Exception\ZMException;
class DBException extends ZMException
{
}

View File

@@ -0,0 +1,128 @@
<?php
/** @noinspection PhpComposerExtensionStubsInspection */
declare(strict_types=1);
namespace ZM\Store\Database;
use OneBot\Driver\Driver;
use OneBot\Driver\Interfaces\PoolInterface;
use OneBot\Driver\Swoole\ObjectPool as SwooleObjectPool;
use OneBot\Driver\Swoole\SwooleDriver;
use OneBot\Driver\Workerman\ObjectPool as WorkermanObjectPool;
use OneBot\Driver\Workerman\WorkermanDriver;
use PDO;
use RuntimeException;
use ZM\Store\FileSystem;
class DBPool
{
/**
* @var array<string, SwooleObjectPool|WorkermanObjectPool> 连接池列表
*/
private static $pools = [];
/**
* 通过配置文件创建一个 MySQL 连接池
*
* @throws DBException
*/
public static function create(string $name, array $config)
{
$size = $config['pool_size'] ?? 64;
switch ($config['type']) {
case 'mysql':
$connect_str = 'mysql:host={host};port={port};dbname={dbname};charset={charset}';
$table = [
'{host}' => $config['host'],
'{port}' => $config['port'],
'{dbname}' => $config['dbname'],
'{charset}' => $config['charset'] ?? 'utf8mb4',
];
$connect_str = str_replace(array_keys($table), array_values($table), $connect_str);
$args = [$config['username'], $config['password'], $config['options'] ?? []];
self::checkMysqlExtension();
break;
case 'sqlite':
$connect_str = 'sqlite:{dbname}';
if (FileSystem::isRelativePath($config['dbname'])) {
$config['dbname'] = zm_dir(SOURCE_ROOT_DIR . '/' . $config['dbname']);
}
$table = [
'{dbname}' => $config['dbname'],
];
$args = [];
$connect_str = str_replace(array_keys($table), array_values($table), $connect_str);
break;
default:
throw new DBException('type ' . $config['type'] . ' not supported yet');
}
switch (Driver::getActiveDriverClass()) {
case WorkermanDriver::class:
self::$pools[$name] = new WorkermanObjectPool($size, PDO::class, $connect_str, ...$args);
break;
case SwooleDriver::class:
self::$pools[$name] = new SwooleObjectPool($size, PDO::class, $connect_str, ...$args);
}
}
/**
* 获取一个数据库连接池
*
* @param string $name 连接池名称
* @return SwooleObjectPool|WorkermanObjectPool
*/
public static function pool(string $name)
{
if (!isset(self::$pools[$name]) && count(self::$pools) !== 1) {
throw new RuntimeException("Pool {$name} not found");
}
return self::$pools[$name] ?? self::$pools[array_key_first(self::$pools)];
}
/**
* 获取所有数据库连接池
*
* @return PoolInterface[]
*/
public static function getAllPools(): array
{
return self::$pools;
}
/**
* 销毁数据库连接池
*
* @param string $name 数据库连接池名称
*/
public static function destroyPool(string $name)
{
unset(self::$pools[$name]);
}
/**
* 检查数据库启动必要的依赖扩展,如果不符合要求则抛出异常
*
* @throws DBException
*/
public static function checkMysqlExtension()
{
ob_start();
phpinfo(); // 这个phpinfo是有用的不能删除
$str = ob_get_clean();
$str = explode("\n", $str);
foreach ($str as $v) {
$v = trim($v);
if ($v == '') {
continue;
}
if (mb_strpos($v, 'API Extensions') === false) {
continue;
}
if (mb_strpos($v, 'pdo_mysql') === false) {
throw new DBException(zm_internal_errcode('E00028') . '未安装 mysqlnd php-mysql扩展。');
}
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace ZM\Store\Database;
use Doctrine\DBAL\Query\QueryBuilder;
use ZM\Store\Database\DBException as DbException;
class DBQueryBuilder extends QueryBuilder
{
private $wrapper;
public function __construct(DBWrapper $wrapper)
{
parent::__construct($wrapper->getConnection());
$this->wrapper = $wrapper;
}
/**
* @throws DbException
* @return DBStatementWrapper|int
*/
public function execute()
{
if ($this->getType() === self::SELECT) {
return $this->wrapper->executeQuery($this->getSQL(), $this->getParameters(), $this->getParameterTypes());
}
return $this->wrapper->executeStatement($this->getSQL(), $this->getParameters(), $this->getParameterTypes());
}
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* @noinspection PhpComposerExtensionStubsInspection
*/
declare(strict_types=1);
namespace ZM\Store\Database;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\ParameterType;
use IteratorAggregate;
use PDO;
use PDOStatement;
use Traversable;
class DBStatement implements IteratorAggregate, Statement
{
/** @var PDOStatement */
private $statement;
public function __construct($obj)
{
$this->statement = $obj;
}
public function closeCursor()
{
return $this->statement->closeCursor();
}
public function columnCount()
{
return $this->statement->columnCount();
}
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = [])
{
if ($arg2 !== null && $arg3 !== []) {
return $this->statement->setFetchMode($fetchMode, $arg2, $arg3);
}
if ($arg2 !== null && $arg3 === []) {
return $this->statement->setFetchMode($fetchMode, $arg2);
}
if ($arg2 === null && $arg3 !== []) {
return $this->statement->setFetchMode($fetchMode, $arg2, $arg3);
}
return $this->statement->setFetchMode($fetchMode);
}
public function fetch($fetchMode = PDO::FETCH_ASSOC, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
{
return $this->statement->fetch($fetchMode, $cursorOrientation, $cursorOffset);
}
public function fetchAll($fetchMode = PDO::FETCH_ASSOC, $fetchArgument = null, $ctorArgs = null)
{
if ($fetchArgument === null && $ctorArgs === null) {
return $this->statement->fetchAll($fetchMode);
}
if ($fetchArgument !== null && $ctorArgs === null) {
return $this->statement->fetchAll($fetchMode, $fetchArgument);
}
return $this->statement->fetchAll($fetchMode, $fetchArgument, $ctorArgs);
}
public function fetchColumn($columnIndex = 0)
{
return $this->statement->fetchColumn($columnIndex);
}
public function bindValue($param, $value, $type = ParameterType::STRING)
{
return $this->statement->bindValue($param, $value, $type);
}
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null)
{
return $this->statement->bindParam($param, $variable, $type, $length);
}
public function errorCode()
{
return $this->statement->errorCode();
}
public function errorInfo()
{
return $this->statement->errorInfo();
}
public function execute($params = null)
{
return $this->statement->execute($params);
}
public function rowCount()
{
return $this->statement->rowCount();
}
public function getIterator(): Traversable
{
while (($result = $this->statement->fetch()) !== false) {
yield $result;
}
}
/**
* @deprecated 最好不使用此方法,此方法可能存在 Bug
* @return mixed
*/
public function current()
{
if (method_exists($this->statement, 'current')) {
return $this->statement->current();
}
return null;
}
}

View File

@@ -0,0 +1,239 @@
<?php
/**
* @noinspection PhpMissingReturnTypeInspection
* @noinspection PhpUnused
*/
declare(strict_types=1);
namespace ZM\Store\Database;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\ForwardCompatibility\Result;
use Throwable;
use Traversable;
class DBStatementWrapper
{
public ?Result $stmt;
public function __construct(?Result $stmt)
{
$this->stmt = $stmt;
}
/**
* 获取结果的迭代器
* wrapper method
* @return ResultStatement
*/
public function getIterator()
{
return $this->stmt->getIterator();
}
/**
* 获取列数
* wrapper method
* @return int
*/
public function columnCount()
{
return $this->stmt->columnCount();
}
/**
* wrapper method
*@throws DBException
* @return array|false|mixed
*/
public function fetchNumeric()
{
try {
return $this->stmt->fetchNumeric();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
*@throws DBException
* @return array|false|mixed
*/
public function fetchAssociative()
{
try {
return $this->stmt->fetchAssociative();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
*@throws DBException
* @return false|mixed
*/
public function fetchOne()
{
try {
return $this->stmt->fetchOne();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function fetchAllNumeric(): array
{
try {
return $this->stmt->fetchAllNumeric();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function fetchAllAssociative(): array
{
try {
return $this->stmt->fetchAllAssociative();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function fetchAllKeyValue(): array
{
try {
return $this->stmt->fetchAllKeyValue();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function fetchAllAssociativeIndexed(): array
{
try {
return $this->stmt->fetchAllAssociativeIndexed();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function fetchFirstColumn(): array
{
try {
return $this->stmt->fetchFirstColumn();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function iterateNumeric(): Traversable
{
try {
return $this->stmt->iterateNumeric();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function iterateAssociative(): Traversable
{
try {
return $this->stmt->iterateAssociative();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function iterateKeyValue(): Traversable
{
try {
return $this->stmt->iterateKeyValue();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function iterateAssociativeIndexed(): Traversable
{
try {
return $this->stmt->iterateAssociativeIndexed();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function iterateColumn(): Traversable
{
try {
return $this->stmt->iterateColumn();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
* @return int
*/
public function rowCount()
{
try {
return $this->stmt->rowCount();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
*/
public function free(): void
{
$this->stmt->free();
}
}

View File

@@ -0,0 +1,615 @@
<?php
declare(strict_types=1);
namespace ZM\Store\Database;
use Closure;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Types\Type;
use Throwable;
use Traversable;
class DBWrapper
{
private Connection $connection;
/**
* DBWrapper constructor.
* @throws DBException
*/
public function __construct(string $name)
{
try {
$db_list = config()->get('global.database');
if (isset($db_list[$name]) || count($db_list) === 1) {
if ($name === '') {
$name = array_key_first($db_list);
}
$this->connection = DriverManager::getConnection(['driverClass' => $this->getConnectionClass($db_list[$name]['type']), 'dbName' => $name]);
} else {
throw new DBException('Cannot find database config named "' . $name . '" !');
}
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
public function __destruct()
{
$this->connection->close();
}
/**
* wrapper method
*/
public function getDatabase(): string
{
return $this->connection->getDatabase();
}
/**
* wrapper method
*/
public function isAutoCommit(): bool
{
return $this->connection->isAutoCommit();
}
/**
* wrapper method
*/
public function setAutoCommit(bool $auto_commit)
{
$this->connection->setAutoCommit($auto_commit);
}
/**
* wrapper method
* @throws DBException
* @return array|false
*/
public function fetchAssociative(string $query, array $params = [], array $types = [])
{
try {
return $this->connection->fetchAssociative($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), intval($e->getCode()), $e);
}
}
/**
* wrapper method
* @throws DBException
* @return array|false
*/
public function fetchNumeric(string $query, array $params = [], array $types = [])
{
try {
return $this->connection->fetchNumeric($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* @throws DBException
* @return false|mixed
*/
public function fetchOne(string $query, array $params = [], array $types = [])
{
try {
return $this->connection->fetchOne($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
*/
public function isTransactionActive(): bool
{
return $this->connection->isTransactionActive();
}
/**
* @param string $table 表
* @throws DBException
*/
public function delete(string $table, array $criteria, array $types = []): int
{
try {
return $this->connection->delete($table, $criteria, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param int $level Sets the transaction isolation level
*/
public function setTransactionIsolation(int $level): int
{
return $this->connection->setTransactionIsolation($level);
}
/**
* wrapper method
*/
public function getTransactionIsolation(): ?int
{
return $this->connection->getTransactionIsolation();
}
/**
* wrapper method
* @param string $table 表名
* @throws DBException
*/
public function update(string $table, array $data, array $criteria, array $types = []): int
{
try {
return $this->connection->update($table, $data, $criteria, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $table 表名
* @throws DBException
*/
public function insert(string $table, array $data, array $types = []): int
{
try {
return $this->connection->insert($table, $data, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $str The name to be quoted
*/
public function quoteIdentifier(string $str): string
{
return $this->connection->quoteIdentifier($str);
}
/**
* wrapper method
* @param mixed $value
* @param null|int|string|Type $type
*/
public function quote($value, $type = ParameterType::STRING)
{
return $this->connection->quote($value, $type);
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @throws DBException
* @return array<int,array<int,mixed>>
*/
public function fetchAllNumeric(string $query, array $params = [], array $types = []): array
{
try {
return $this->connection->fetchAllNumeric($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @throws DBException
* @return array<int,array<string,mixed>>
*/
public function fetchAllAssociative(string $query, array $params = [], array $types = []): array
{
try {
return $this->connection->fetchAllAssociative($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string>|array<string, int|string> $types Parameter types
*
* @throws DBException
*/
public function fetchAllKeyValue(string $query, array $params = [], array $types = []): array
{
try {
return $this->connection->fetchAllKeyValue($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string>|array<string, int|string> $types Parameter types
*
* @throws DBException
* @return array<mixed,array<string,mixed>>
*/
public function fetchAllAssociativeIndexed(string $query, array $params = [], array $types = []): array
{
try {
return $this->connection->fetchAllAssociativeIndexed($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @throws DBException
* @return array<int,mixed>
*/
public function fetchFirstColumn(string $query, array $params = [], array $types = []): array
{
try {
return $this->connection->fetchFirstColumn($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @throws DBException
* @return Traversable<int,array<int,mixed>>
*/
public function iterateNumeric(string $query, array $params = [], array $types = []): Traversable
{
try {
return $this->connection->iterateNumeric($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @throws DBException
* @return Traversable<int,array<string,mixed>>
*/
public function iterateAssociative(string $query, array $params = [], array $types = []): Traversable
{
try {
return $this->connection->iterateAssociative($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string>|array<string, int|string> $types Parameter types
*
* @throws DBException
* @return Traversable<mixed,mixed>
*/
public function iterateKeyValue(string $query, array $params = [], array $types = []): Traversable
{
try {
return $this->connection->iterateKeyValue($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string>|array<string, int|string> $types Parameter types
*
* @throws DBException
* @return Traversable<mixed,array<string,mixed>>
*/
public function iterateAssociativeIndexed(string $query, array $params = [], array $types = []): Traversable
{
try {
return $this->connection->iterateAssociativeIndexed($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $query SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @throws DBException
* @return Traversable<int,mixed>
*/
public function iterateColumn(string $query, array $params = [], array $types = []): Traversable
{
try {
return $this->connection->iterateColumn($query, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $sql SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @throws DBException
*/
public function executeQuery(string $sql, array $params = [], array $types = [], ?QueryCacheProfile $qcp = null): DBStatementWrapper
{
try {
$query = $this->connection->executeQuery($sql, $params, $types, $qcp);
return new DBStatementWrapper($query);
} catch (Throwable $e) {
throw $e;
// throw new DBException($e->getMessage(), intval($e->getCode()), $e);
}
}
/**
* wrapper method
* @param string $sql SQL query
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
* @throws DBException
*/
public function executeCacheQuery(string $sql, array $params, array $types, QueryCacheProfile $qcp): DBStatementWrapper
{
try {
$query = $this->connection->executeCacheQuery($sql, $params, $types, $qcp);
return new DBStatementWrapper($query);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $sql SQL statement
* @param array<int, mixed>|array<string, mixed> $params Statement parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @throws DBException
* @return int|string the number of affected rows
*/
public function executeStatement(string $sql, array $params = [], array $types = [])
{
try {
return $this->connection->executeStatement($sql, $params, $types);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
*/
public function getTransactionNestingLevel(): int
{
return $this->connection->getTransactionNestingLevel();
}
/**
* wrapper method
* @param null|string $name name of the sequence object from which the ID should be returned
* @return false|int|string a string representation of the last inserted ID
*/
public function lastInsertId(?string $name = null)
{
return $this->connection->lastInsertId($name);
}
/**
* overwrite method to $this->connection->transactional()
* @throws DBException
* @return mixed
*/
public function transactional(Closure $func)
{
$this->beginTransaction();
try {
$res = $func($this);
$this->commit();
return $res;
} catch (Throwable $e) {
$this->rollBack();
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function setNestTransactionsWithSavepoints(bool $nest_transactions_with_savepoints)
{
try {
$this->connection->setNestTransactionsWithSavepoints($nest_transactions_with_savepoints);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
*/
public function getNestTransactionsWithSavepoints(): bool
{
return $this->connection->getNestTransactionsWithSavepoints();
}
/**
* wrapper method
*/
public function beginTransaction(): bool
{
return $this->connection->beginTransaction();
}
/**
* wrapper method
* @throws DBException
*/
public function commit(): bool
{
try {
return $this->connection->commit();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function rollBack(): bool
{
try {
return $this->connection->rollBack();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $savepoint the name of the savepoint to create
* @throws DBException
*/
public function createSavepoint(string $savepoint)
{
try {
$this->connection->createSavepoint($savepoint);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $savepoint the name of the savepoint to release
* @throws DBException
*/
public function releaseSavepoint(string $savepoint)
{
try {
$this->connection->releaseSavepoint($savepoint);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @param string $savepoint the name of the savepoint to rollback to
* @throws DBException
*/
public function rollbackSavepoint(string $savepoint)
{
try {
$this->connection->rollbackSavepoint($savepoint);
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function setRollbackOnly()
{
try {
$this->connection->setRollbackOnly();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* wrapper method
* @throws DBException
*/
public function isRollbackOnly(): bool
{
try {
return $this->connection->isRollbackOnly();
} catch (Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* overwrite method to $this->connection->createQueryBuilder
*/
public function createQueryBuilder(): DBQueryBuilder
{
return new DBQueryBuilder($this);
}
public function getConnection(): Connection
{
return $this->connection;
}
/**
* @throws DBException
*/
private function getConnectionClass(string $type): string
{
switch ($type) {
case 'mysql':
return MySQLDriver::class;
case 'sqlite':
return SQLiteDriver::class;
default:
throw new DBException('Unknown database type: ' . $type);
}
}
}