Update website
This commit is contained in:
parent
4413528994
commit
1d90fbf296
6865 changed files with 1091082 additions and 0 deletions
141
vendor/doctrine/dbal/src/Driver/Mysqli/Connection.php
vendored
Normal file
141
vendor/doctrine/dbal/src/Driver/Mysqli/Connection.php
vendored
Normal file
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli;
|
||||
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\ConnectionError;
|
||||
use Doctrine\DBAL\Driver\Result as ResultInterface;
|
||||
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
|
||||
use Doctrine\DBAL\Driver\Statement as DriverStatement;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
|
||||
final class Connection implements ServerInfoAwareConnection
|
||||
{
|
||||
/**
|
||||
* Name of the option to set connection flags
|
||||
*/
|
||||
public const OPTION_FLAGS = 'flags';
|
||||
|
||||
private mysqli $connection;
|
||||
|
||||
/** @internal The connection can be only instantiated by its driver. */
|
||||
public function __construct(mysqli $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves mysqli native resource handle.
|
||||
*
|
||||
* Could be used if part of your application is not using DBAL.
|
||||
*
|
||||
* @deprecated Call {@see getNativeConnection()} instead.
|
||||
*/
|
||||
public function getWrappedResourceHandle(): mysqli
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/pull/5037',
|
||||
'%s is deprecated, call getNativeConnection() instead.',
|
||||
__METHOD__,
|
||||
);
|
||||
|
||||
return $this->getNativeConnection();
|
||||
}
|
||||
|
||||
public function getServerVersion(): string
|
||||
{
|
||||
return $this->connection->get_server_info();
|
||||
}
|
||||
|
||||
public function prepare(string $sql): DriverStatement
|
||||
{
|
||||
try {
|
||||
$stmt = $this->connection->prepare($sql);
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw ConnectionError::upcast($e);
|
||||
}
|
||||
|
||||
if ($stmt === false) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
|
||||
return new Statement($stmt);
|
||||
}
|
||||
|
||||
public function query(string $sql): ResultInterface
|
||||
{
|
||||
return $this->prepare($sql)->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function quote($value, $type = ParameterType::STRING)
|
||||
{
|
||||
return "'" . $this->connection->escape_string($value) . "'";
|
||||
}
|
||||
|
||||
public function exec(string $sql): int
|
||||
{
|
||||
try {
|
||||
$result = $this->connection->query($sql);
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw ConnectionError::upcast($e);
|
||||
}
|
||||
|
||||
if ($result === false) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
|
||||
return $this->connection->affected_rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function lastInsertId($name = null)
|
||||
{
|
||||
if ($name !== null) {
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/issues/4687',
|
||||
'The usage of Connection::lastInsertId() with a sequence name is deprecated.',
|
||||
);
|
||||
}
|
||||
|
||||
return $this->connection->insert_id;
|
||||
}
|
||||
|
||||
public function beginTransaction(): bool
|
||||
{
|
||||
$this->connection->begin_transaction();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function commit(): bool
|
||||
{
|
||||
try {
|
||||
return $this->connection->commit();
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function rollBack(): bool
|
||||
{
|
||||
try {
|
||||
return $this->connection->rollback();
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getNativeConnection(): mysqli
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
}
|
117
vendor/doctrine/dbal/src/Driver/Mysqli/Driver.php
vendored
Normal file
117
vendor/doctrine/dbal/src/Driver/Mysqli/Driver.php
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractMySQLDriver;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\ConnectionFailed;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\HostRequired;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Initializer\Charset;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Initializer\Options;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Initializer\Secure;
|
||||
use Generator;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
use SensitiveParameter;
|
||||
|
||||
final class Driver extends AbstractMySQLDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return Connection
|
||||
*/
|
||||
public function connect(
|
||||
#[SensitiveParameter]
|
||||
array $params
|
||||
) {
|
||||
if (! empty($params['persistent'])) {
|
||||
if (! isset($params['host'])) {
|
||||
throw HostRequired::forPersistentConnection();
|
||||
}
|
||||
|
||||
$host = 'p:' . $params['host'];
|
||||
} else {
|
||||
$host = $params['host'] ?? null;
|
||||
}
|
||||
|
||||
$connection = new mysqli();
|
||||
|
||||
foreach ($this->compilePreInitializers($params) as $initializer) {
|
||||
$initializer->initialize($connection);
|
||||
}
|
||||
|
||||
try {
|
||||
$success = @$connection->real_connect(
|
||||
$host,
|
||||
$params['user'] ?? null,
|
||||
$params['password'] ?? null,
|
||||
$params['dbname'] ?? null,
|
||||
$params['port'] ?? null,
|
||||
$params['unix_socket'] ?? null,
|
||||
$params['driverOptions'][Connection::OPTION_FLAGS] ?? 0,
|
||||
);
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw ConnectionFailed::upcast($e);
|
||||
}
|
||||
|
||||
if (! $success) {
|
||||
throw ConnectionFailed::new($connection);
|
||||
}
|
||||
|
||||
foreach ($this->compilePostInitializers($params) as $initializer) {
|
||||
$initializer->initialize($connection);
|
||||
}
|
||||
|
||||
return new Connection($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $params
|
||||
*
|
||||
* @return Generator<int, Initializer>
|
||||
*/
|
||||
private function compilePreInitializers(
|
||||
#[SensitiveParameter]
|
||||
array $params
|
||||
): Generator {
|
||||
unset($params['driverOptions'][Connection::OPTION_FLAGS]);
|
||||
|
||||
if (isset($params['driverOptions']) && $params['driverOptions'] !== []) {
|
||||
yield new Options($params['driverOptions']);
|
||||
}
|
||||
|
||||
if (
|
||||
! isset($params['ssl_key']) &&
|
||||
! isset($params['ssl_cert']) &&
|
||||
! isset($params['ssl_ca']) &&
|
||||
! isset($params['ssl_capath']) &&
|
||||
! isset($params['ssl_cipher'])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield new Secure(
|
||||
$params['ssl_key'] ?? '',
|
||||
$params['ssl_cert'] ?? '',
|
||||
$params['ssl_ca'] ?? '',
|
||||
$params['ssl_capath'] ?? '',
|
||||
$params['ssl_cipher'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $params
|
||||
*
|
||||
* @return Generator<int, Initializer>
|
||||
*/
|
||||
private function compilePostInitializers(
|
||||
#[SensitiveParameter]
|
||||
array $params
|
||||
): Generator {
|
||||
if (! isset($params['charset'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield new Charset($params['charset']);
|
||||
}
|
||||
}
|
31
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionError.php
vendored
Normal file
31
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionError.php
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class ConnectionError extends AbstractException
|
||||
{
|
||||
public static function new(mysqli $connection): self
|
||||
{
|
||||
return new self($connection->error, $connection->sqlstate, $connection->errno);
|
||||
}
|
||||
|
||||
public static function upcast(mysqli_sql_exception $exception): self
|
||||
{
|
||||
$p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate');
|
||||
$p->setAccessible(true);
|
||||
|
||||
return new self($exception->getMessage(), $p->getValue($exception), (int) $exception->getCode(), $exception);
|
||||
}
|
||||
}
|
36
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionFailed.php
vendored
Normal file
36
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionFailed.php
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function assert;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class ConnectionFailed extends AbstractException
|
||||
{
|
||||
public static function new(mysqli $connection): self
|
||||
{
|
||||
$error = $connection->connect_error;
|
||||
assert($error !== null);
|
||||
|
||||
return new self($error, 'HY000', $connection->connect_errno);
|
||||
}
|
||||
|
||||
public static function upcast(mysqli_sql_exception $exception): self
|
||||
{
|
||||
$p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate');
|
||||
$p->setAccessible(true);
|
||||
|
||||
return new self($exception->getMessage(), $p->getValue($exception), (int) $exception->getCode(), $exception);
|
||||
}
|
||||
}
|
22
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/FailedReadingStreamOffset.php
vendored
Normal file
22
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/FailedReadingStreamOffset.php
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class FailedReadingStreamOffset extends AbstractException
|
||||
{
|
||||
public static function new(int $parameter): self
|
||||
{
|
||||
return new self(sprintf('Failed reading the stream resource for parameter #%d.', $parameter));
|
||||
}
|
||||
}
|
20
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/HostRequired.php
vendored
Normal file
20
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/HostRequired.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class HostRequired extends AbstractException
|
||||
{
|
||||
public static function forPersistentConnection(): self
|
||||
{
|
||||
return new self('The "host" parameter is required for a persistent connection');
|
||||
}
|
||||
}
|
42
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidCharset.php
vendored
Normal file
42
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidCharset.php
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class InvalidCharset extends AbstractException
|
||||
{
|
||||
public static function fromCharset(mysqli $connection, string $charset): self
|
||||
{
|
||||
return new self(
|
||||
sprintf('Failed to set charset "%s": %s', $charset, $connection->error),
|
||||
$connection->sqlstate,
|
||||
$connection->errno,
|
||||
);
|
||||
}
|
||||
|
||||
public static function upcast(mysqli_sql_exception $exception, string $charset): self
|
||||
{
|
||||
$p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate');
|
||||
$p->setAccessible(true);
|
||||
|
||||
return new self(
|
||||
sprintf('Failed to set charset "%s": %s', $charset, $exception->getMessage()),
|
||||
$p->getValue($exception),
|
||||
(int) $exception->getCode(),
|
||||
$exception,
|
||||
);
|
||||
}
|
||||
}
|
25
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidOption.php
vendored
Normal file
25
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidOption.php
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class InvalidOption extends AbstractException
|
||||
{
|
||||
/** @param mixed $value */
|
||||
public static function fromOption(int $option, $value): self
|
||||
{
|
||||
return new self(
|
||||
sprintf('Failed to set option %d with value "%s"', $option, $value),
|
||||
);
|
||||
}
|
||||
}
|
24
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/NonStreamResourceUsedAsLargeObject.php
vendored
Normal file
24
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/NonStreamResourceUsedAsLargeObject.php
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class NonStreamResourceUsedAsLargeObject extends AbstractException
|
||||
{
|
||||
public static function new(int $parameter): self
|
||||
{
|
||||
return new self(
|
||||
sprintf('The resource passed as a LARGE_OBJECT parameter #%d must be of type "stream"', $parameter),
|
||||
);
|
||||
}
|
||||
}
|
31
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/StatementError.php
vendored
Normal file
31
vendor/doctrine/dbal/src/Driver/Mysqli/Exception/StatementError.php
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
use mysqli_sql_exception;
|
||||
use mysqli_stmt;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class StatementError extends AbstractException
|
||||
{
|
||||
public static function new(mysqli_stmt $statement): self
|
||||
{
|
||||
return new self($statement->error, $statement->sqlstate, $statement->errno);
|
||||
}
|
||||
|
||||
public static function upcast(mysqli_sql_exception $exception): self
|
||||
{
|
||||
$p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate');
|
||||
$p->setAccessible(true);
|
||||
|
||||
return new self($exception->getMessage(), $p->getValue($exception), (int) $exception->getCode(), $exception);
|
||||
}
|
||||
}
|
14
vendor/doctrine/dbal/src/Driver/Mysqli/Initializer.php
vendored
Normal file
14
vendor/doctrine/dbal/src/Driver/Mysqli/Initializer.php
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli;
|
||||
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use mysqli;
|
||||
|
||||
interface Initializer
|
||||
{
|
||||
/** @throws Exception */
|
||||
public function initialize(mysqli $connection): void;
|
||||
}
|
35
vendor/doctrine/dbal/src/Driver/Mysqli/Initializer/Charset.php
vendored
Normal file
35
vendor/doctrine/dbal/src/Driver/Mysqli/Initializer/Charset.php
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Initializer;
|
||||
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\InvalidCharset;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Initializer;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
|
||||
final class Charset implements Initializer
|
||||
{
|
||||
private string $charset;
|
||||
|
||||
public function __construct(string $charset)
|
||||
{
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
public function initialize(mysqli $connection): void
|
||||
{
|
||||
try {
|
||||
$success = $connection->set_charset($this->charset);
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw InvalidCharset::upcast($e, $this->charset);
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw InvalidCharset::fromCharset($connection, $this->charset);
|
||||
}
|
||||
}
|
32
vendor/doctrine/dbal/src/Driver/Mysqli/Initializer/Options.php
vendored
Normal file
32
vendor/doctrine/dbal/src/Driver/Mysqli/Initializer/Options.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Initializer;
|
||||
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\InvalidOption;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Initializer;
|
||||
use mysqli;
|
||||
|
||||
use function mysqli_options;
|
||||
|
||||
final class Options implements Initializer
|
||||
{
|
||||
/** @var array<int,mixed> */
|
||||
private array $options;
|
||||
|
||||
/** @param array<int,mixed> $options */
|
||||
public function __construct(array $options)
|
||||
{
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
public function initialize(mysqli $connection): void
|
||||
{
|
||||
foreach ($this->options as $option => $value) {
|
||||
if (! mysqli_options($connection, $option, $value)) {
|
||||
throw InvalidOption::fromOption($option, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
vendor/doctrine/dbal/src/Driver/Mysqli/Initializer/Secure.php
vendored
Normal file
38
vendor/doctrine/dbal/src/Driver/Mysqli/Initializer/Secure.php
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Initializer;
|
||||
|
||||
use Doctrine\DBAL\Driver\Mysqli\Initializer;
|
||||
use mysqli;
|
||||
use SensitiveParameter;
|
||||
|
||||
final class Secure implements Initializer
|
||||
{
|
||||
private string $key;
|
||||
private string $cert;
|
||||
private string $ca;
|
||||
private string $capath;
|
||||
private string $cipher;
|
||||
|
||||
public function __construct(
|
||||
#[SensitiveParameter]
|
||||
string $key,
|
||||
string $cert,
|
||||
string $ca,
|
||||
string $capath,
|
||||
string $cipher
|
||||
) {
|
||||
$this->key = $key;
|
||||
$this->cert = $cert;
|
||||
$this->ca = $ca;
|
||||
$this->capath = $capath;
|
||||
$this->cipher = $cipher;
|
||||
}
|
||||
|
||||
public function initialize(mysqli $connection): void
|
||||
{
|
||||
$connection->ssl_set($this->key, $this->cert, $this->ca, $this->capath, $this->cipher);
|
||||
}
|
||||
}
|
179
vendor/doctrine/dbal/src/Driver/Mysqli/Result.php
vendored
Normal file
179
vendor/doctrine/dbal/src/Driver/Mysqli/Result.php
vendored
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli;
|
||||
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Driver\FetchUtils;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\StatementError;
|
||||
use Doctrine\DBAL\Driver\Result as ResultInterface;
|
||||
use mysqli_sql_exception;
|
||||
use mysqli_stmt;
|
||||
|
||||
use function array_column;
|
||||
use function array_combine;
|
||||
use function array_fill;
|
||||
use function count;
|
||||
|
||||
final class Result implements ResultInterface
|
||||
{
|
||||
private mysqli_stmt $statement;
|
||||
|
||||
/**
|
||||
* Whether the statement result has columns. The property should be used only after the result metadata
|
||||
* has been fetched ({@see $metadataFetched}). Otherwise, the property value is undetermined.
|
||||
*/
|
||||
private bool $hasColumns = false;
|
||||
|
||||
/**
|
||||
* Mapping of statement result column indexes to their names. The property should be used only
|
||||
* if the statement result has columns ({@see $hasColumns}). Otherwise, the property value is undetermined.
|
||||
*
|
||||
* @var array<int,string>
|
||||
*/
|
||||
private array $columnNames = [];
|
||||
|
||||
/** @var mixed[] */
|
||||
private array $boundValues = [];
|
||||
|
||||
/**
|
||||
* @internal The result can be only instantiated by its driver connection or statement.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(mysqli_stmt $statement)
|
||||
{
|
||||
$this->statement = $statement;
|
||||
|
||||
$meta = $statement->result_metadata();
|
||||
|
||||
if ($meta === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->hasColumns = true;
|
||||
|
||||
$this->columnNames = array_column($meta->fetch_fields(), 'name');
|
||||
|
||||
$meta->free();
|
||||
|
||||
// Store result of every execution which has it. Otherwise it will be impossible
|
||||
// to execute a new statement in case if the previous one has non-fetched rows
|
||||
// @link http://dev.mysql.com/doc/refman/5.7/en/commands-out-of-sync.html
|
||||
$this->statement->store_result();
|
||||
|
||||
// Bind row values _after_ storing the result. Otherwise, if mysqli is compiled with libmysql,
|
||||
// it will have to allocate as much memory as it may be needed for the given column type
|
||||
// (e.g. for a LONGBLOB column it's 4 gigabytes)
|
||||
// @link https://bugs.php.net/bug.php?id=51386#1270673122
|
||||
//
|
||||
// Make sure that the values are bound after each execution. Otherwise, if free() has been
|
||||
// previously called on the result, the values are unbound making the statement unusable.
|
||||
//
|
||||
// It's also important that row values are bound after _each_ call to store_result(). Otherwise,
|
||||
// if mysqli is compiled with libmysql, subsequently fetched string values will get truncated
|
||||
// to the length of the ones fetched during the previous execution.
|
||||
$this->boundValues = array_fill(0, count($this->columnNames), null);
|
||||
|
||||
// The following is necessary as PHP cannot handle references to properties properly
|
||||
$refs = &$this->boundValues;
|
||||
|
||||
if (! $this->statement->bind_result(...$refs)) {
|
||||
throw StatementError::new($this->statement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchNumeric()
|
||||
{
|
||||
try {
|
||||
$ret = $this->statement->fetch();
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw StatementError::upcast($e);
|
||||
}
|
||||
|
||||
if ($ret === false) {
|
||||
throw StatementError::new($this->statement);
|
||||
}
|
||||
|
||||
if ($ret === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$values = [];
|
||||
|
||||
foreach ($this->boundValues as $v) {
|
||||
$values[] = $v;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchAssociative()
|
||||
{
|
||||
$values = $this->fetchNumeric();
|
||||
|
||||
if ($values === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_combine($this->columnNames, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchOne()
|
||||
{
|
||||
return FetchUtils::fetchOne($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchAllNumeric(): array
|
||||
{
|
||||
return FetchUtils::fetchAllNumeric($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchAllAssociative(): array
|
||||
{
|
||||
return FetchUtils::fetchAllAssociative($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchFirstColumn(): array
|
||||
{
|
||||
return FetchUtils::fetchFirstColumn($this);
|
||||
}
|
||||
|
||||
public function rowCount(): int
|
||||
{
|
||||
if ($this->hasColumns) {
|
||||
return $this->statement->num_rows;
|
||||
}
|
||||
|
||||
return $this->statement->affected_rows;
|
||||
}
|
||||
|
||||
public function columnCount(): int
|
||||
{
|
||||
return $this->statement->field_count;
|
||||
}
|
||||
|
||||
public function free(): void
|
||||
{
|
||||
$this->statement->free_result();
|
||||
}
|
||||
}
|
239
vendor/doctrine/dbal/src/Driver/Mysqli/Statement.php
vendored
Normal file
239
vendor/doctrine/dbal/src/Driver/Mysqli/Statement.php
vendored
Normal file
|
@ -0,0 +1,239 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli;
|
||||
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Driver\Exception\UnknownParameterType;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\FailedReadingStreamOffset;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\NonStreamResourceUsedAsLargeObject;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\StatementError;
|
||||
use Doctrine\DBAL\Driver\Result as ResultInterface;
|
||||
use Doctrine\DBAL\Driver\Statement as StatementInterface;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use mysqli_sql_exception;
|
||||
use mysqli_stmt;
|
||||
|
||||
use function array_fill;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function feof;
|
||||
use function fread;
|
||||
use function func_num_args;
|
||||
use function get_resource_type;
|
||||
use function is_int;
|
||||
use function is_resource;
|
||||
use function str_repeat;
|
||||
|
||||
final class Statement implements StatementInterface
|
||||
{
|
||||
private const PARAM_TYPE_MAP = [
|
||||
ParameterType::ASCII => 's',
|
||||
ParameterType::STRING => 's',
|
||||
ParameterType::BINARY => 's',
|
||||
ParameterType::BOOLEAN => 'i',
|
||||
ParameterType::NULL => 's',
|
||||
ParameterType::INTEGER => 'i',
|
||||
ParameterType::LARGE_OBJECT => 'b',
|
||||
];
|
||||
|
||||
private mysqli_stmt $stmt;
|
||||
|
||||
/** @var mixed[] */
|
||||
private array $boundValues;
|
||||
|
||||
private string $types;
|
||||
|
||||
/**
|
||||
* Contains ref values for bindValue().
|
||||
*
|
||||
* @var mixed[]
|
||||
*/
|
||||
private array $values = [];
|
||||
|
||||
/** @internal The statement can be only instantiated by its driver connection. */
|
||||
public function __construct(mysqli_stmt $stmt)
|
||||
{
|
||||
$this->stmt = $stmt;
|
||||
|
||||
$paramCount = $this->stmt->param_count;
|
||||
$this->types = str_repeat('s', $paramCount);
|
||||
$this->boundValues = array_fill(1, $paramCount, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@see bindValue()} instead.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-assert ParameterType::* $type
|
||||
*/
|
||||
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/pull/5563',
|
||||
'%s is deprecated. Use bindValue() instead.',
|
||||
__METHOD__,
|
||||
);
|
||||
|
||||
assert(is_int($param));
|
||||
|
||||
if (func_num_args() < 3) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/pull/5558',
|
||||
'Not passing $type to Statement::bindParam() is deprecated.'
|
||||
. ' Pass the type corresponding to the parameter being bound.',
|
||||
);
|
||||
}
|
||||
|
||||
if (! isset(self::PARAM_TYPE_MAP[$type])) {
|
||||
throw UnknownParameterType::new($type);
|
||||
}
|
||||
|
||||
$this->boundValues[$param] =& $variable;
|
||||
$this->types[$param - 1] = self::PARAM_TYPE_MAP[$type];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-assert ParameterType::* $type
|
||||
*/
|
||||
public function bindValue($param, $value, $type = ParameterType::STRING): bool
|
||||
{
|
||||
assert(is_int($param));
|
||||
|
||||
if (func_num_args() < 3) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/pull/5558',
|
||||
'Not passing $type to Statement::bindValue() is deprecated.'
|
||||
. ' Pass the type corresponding to the parameter being bound.',
|
||||
);
|
||||
}
|
||||
|
||||
if (! isset(self::PARAM_TYPE_MAP[$type])) {
|
||||
throw UnknownParameterType::new($type);
|
||||
}
|
||||
|
||||
$this->values[$param] = $value;
|
||||
$this->boundValues[$param] =& $this->values[$param];
|
||||
$this->types[$param - 1] = self::PARAM_TYPE_MAP[$type];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function execute($params = null): ResultInterface
|
||||
{
|
||||
if ($params !== null) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/pull/5556',
|
||||
'Passing $params to Statement::execute() is deprecated. Bind parameters using'
|
||||
. ' Statement::bindParam() or Statement::bindValue() instead.',
|
||||
);
|
||||
}
|
||||
|
||||
if ($params !== null && count($params) > 0) {
|
||||
if (! $this->bindUntypedValues($params)) {
|
||||
throw StatementError::new($this->stmt);
|
||||
}
|
||||
} elseif (count($this->boundValues) > 0) {
|
||||
$this->bindTypedParameters();
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->stmt->execute();
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw StatementError::upcast($e);
|
||||
}
|
||||
|
||||
if (! $result) {
|
||||
throw StatementError::new($this->stmt);
|
||||
}
|
||||
|
||||
return new Result($this->stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds parameters with known types previously bound to the statement
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function bindTypedParameters(): void
|
||||
{
|
||||
$streams = $values = [];
|
||||
$types = $this->types;
|
||||
|
||||
foreach ($this->boundValues as $parameter => $value) {
|
||||
assert(is_int($parameter));
|
||||
|
||||
if (! isset($types[$parameter - 1])) {
|
||||
$types[$parameter - 1] = self::PARAM_TYPE_MAP[ParameterType::STRING];
|
||||
}
|
||||
|
||||
if ($types[$parameter - 1] === self::PARAM_TYPE_MAP[ParameterType::LARGE_OBJECT]) {
|
||||
if (is_resource($value)) {
|
||||
if (get_resource_type($value) !== 'stream') {
|
||||
throw NonStreamResourceUsedAsLargeObject::new($parameter);
|
||||
}
|
||||
|
||||
$streams[$parameter] = $value;
|
||||
$values[$parameter] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
$types[$parameter - 1] = self::PARAM_TYPE_MAP[ParameterType::STRING];
|
||||
}
|
||||
|
||||
$values[$parameter] = $value;
|
||||
}
|
||||
|
||||
if (! $this->stmt->bind_param($types, ...$values)) {
|
||||
throw StatementError::new($this->stmt);
|
||||
}
|
||||
|
||||
$this->sendLongData($streams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle $this->_longData after regular query parameters have been bound
|
||||
*
|
||||
* @param array<int, resource> $streams
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function sendLongData(array $streams): void
|
||||
{
|
||||
foreach ($streams as $paramNr => $stream) {
|
||||
while (! feof($stream)) {
|
||||
$chunk = fread($stream, 8192);
|
||||
|
||||
if ($chunk === false) {
|
||||
throw FailedReadingStreamOffset::new($paramNr);
|
||||
}
|
||||
|
||||
if (! $this->stmt->send_long_data($paramNr - 1, $chunk)) {
|
||||
throw StatementError::new($this->stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a array of values to bound parameters.
|
||||
*
|
||||
* @param mixed[] $values
|
||||
*/
|
||||
private function bindUntypedValues(array $values): bool
|
||||
{
|
||||
return $this->stmt->bind_param(str_repeat('s', count($values)), ...$values);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue