Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/Driver/Mysqli/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,17 @@ public function getServerVersion()

public function prepare(string $sql): DriverStatement
{
return new Statement($this->conn, $sql);
try {
$stmt = $this->conn->prepare($sql);
} catch (mysqli_sql_exception $e) {
throw ConnectionError::upcast($e);
}

if ($stmt === false) {
throw ConnectionError::new($this->conn);
}

return new Statement($stmt);
}

public function query(string $sql): ResultInterface
Expand Down
89 changes: 33 additions & 56 deletions src/Driver/Mysqli/Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@

use Doctrine\DBAL\Driver\Exception;
use Doctrine\DBAL\Driver\Exception\UnknownParameterType;
use Doctrine\DBAL\Driver\Mysqli\Exception\ConnectionError;
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 mysqli;
use mysqli_sql_exception;
use mysqli_stmt;

Expand All @@ -28,7 +26,7 @@
final class Statement implements StatementInterface
{
/** @var string[] */
protected static $_paramTypeMap = [
private static $paramTypeMap = [
ParameterType::ASCII => 's',
ParameterType::STRING => 's',
ParameterType::BINARY => 's',
Expand All @@ -38,55 +36,36 @@ final class Statement implements StatementInterface
ParameterType::LARGE_OBJECT => 'b',
];

/** @var mysqli */
protected $_conn;

/** @var mysqli_stmt */
protected $_stmt;
private $stmt;

/** @var mixed[]|null */
protected $_bindedValues;
private $boundValues;

/** @var string */
protected $types;
private $types;

/**
* Contains ref values for bindValue().
*
* @var mixed[]
*/
protected $_values = [];
private $values = [];

/**
* @internal The statement can be only instantiated by its driver connection.
*
* @param string $prepareString
*
* @throws Exception
*/
public function __construct(mysqli $conn, $prepareString)
public function __construct(mysqli_stmt $stmt)
{
$this->_conn = $conn;

try {
$stmt = $conn->prepare($prepareString);
} catch (mysqli_sql_exception $e) {
throw ConnectionError::upcast($e);
}

if ($stmt === false) {
throw ConnectionError::new($this->_conn);
}

$this->_stmt = $stmt;
$this->stmt = $stmt;

$paramCount = $this->_stmt->param_count;
$paramCount = $this->stmt->param_count;
if (0 >= $paramCount) {
return;
}

$this->types = str_repeat('s', $paramCount);
$this->_bindedValues = array_fill(1, $paramCount, null);
$this->types = str_repeat('s', $paramCount);
$this->boundValues = array_fill(1, $paramCount, null);
}

/**
Expand All @@ -96,12 +75,12 @@ public function bindParam($param, &$variable, $type = ParameterType::STRING, $le
{
assert(is_int($param));

if (! isset(self::$_paramTypeMap[$type])) {
if (! isset(self::$paramTypeMap[$type])) {
throw UnknownParameterType::new($type);
}

$this->_bindedValues[$param] =& $variable;
$this->types[$param - 1] = self::$_paramTypeMap[$type];
$this->boundValues[$param] =& $variable;
$this->types[$param - 1] = self::$paramTypeMap[$type];

return true;
}
Expand All @@ -113,13 +92,13 @@ public function bindValue($param, $value, $type = ParameterType::STRING)
{
assert(is_int($param));

if (! isset(self::$_paramTypeMap[$type])) {
if (! isset(self::$paramTypeMap[$type])) {
throw UnknownParameterType::new($type);
}

$this->_values[$param] = $value;
$this->_bindedValues[$param] =& $this->_values[$param];
$this->types[$param - 1] = self::$_paramTypeMap[$type];
$this->values[$param] = $value;
$this->boundValues[$param] =& $this->values[$param];
$this->types[$param - 1] = self::$paramTypeMap[$type];

return true;
}
Expand All @@ -129,27 +108,27 @@ public function bindValue($param, $value, $type = ParameterType::STRING)
*/
public function execute($params = null): ResultInterface
{
if ($this->_bindedValues !== null) {
if ($this->boundValues !== null) {
if ($params !== null) {
if (! $this->bindUntypedValues($params)) {
throw StatementError::new($this->_stmt);
throw StatementError::new($this->stmt);
}
} else {
$this->bindTypedParameters();
}
}

try {
$result = $this->_stmt->execute();
$result = $this->stmt->execute();
} catch (mysqli_sql_exception $e) {
throw StatementError::upcast($e);
}

if (! $result) {
throw StatementError::new($this->_stmt);
throw StatementError::new($this->stmt);
}

return new Result($this->_stmt);
return new Result($this->stmt);
}

/**
Expand All @@ -162,16 +141,16 @@ private function bindTypedParameters(): void
$streams = $values = [];
$types = $this->types;

assert($this->_bindedValues !== null);
assert($this->boundValues !== null);

foreach ($this->_bindedValues as $parameter => $value) {
foreach ($this->boundValues as $parameter => $value) {
assert(is_int($parameter));

if (! isset($types[$parameter - 1])) {
$types[$parameter - 1] = static::$_paramTypeMap[ParameterType::STRING];
$types[$parameter - 1] = self::$paramTypeMap[ParameterType::STRING];
}

if ($types[$parameter - 1] === static::$_paramTypeMap[ParameterType::LARGE_OBJECT]) {
if ($types[$parameter - 1] === self::$paramTypeMap[ParameterType::LARGE_OBJECT]) {
if (is_resource($value)) {
if (get_resource_type($value) !== 'stream') {
throw NonStreamResourceUsedAsLargeObject::new($parameter);
Expand All @@ -182,14 +161,14 @@ private function bindTypedParameters(): void
continue;
}

$types[$parameter - 1] = static::$_paramTypeMap[ParameterType::STRING];
$types[$parameter - 1] = self::$paramTypeMap[ParameterType::STRING];
}

$values[$parameter] = $value;
}

if (! $this->_stmt->bind_param($types, ...$values)) {
throw StatementError::new($this->_stmt);
if (! $this->stmt->bind_param($types, ...$values)) {
throw StatementError::new($this->stmt);
}

$this->sendLongData($streams);
Expand All @@ -212,8 +191,8 @@ private function sendLongData(array $streams): void
throw FailedReadingStreamOffset::new($paramNr);
}

if (! $this->_stmt->send_long_data($paramNr - 1, $chunk)) {
throw StatementError::new($this->_stmt);
if (! $this->stmt->send_long_data($paramNr - 1, $chunk)) {
throw StatementError::new($this->stmt);
}
}
}
Expand All @@ -223,10 +202,8 @@ private function sendLongData(array $streams): void
* Binds a array of values to bound parameters.
*
* @param mixed[] $values
*
* @return bool
*/
private function bindUntypedValues(array $values)
private function bindUntypedValues(array $values): bool
{
$params = [];
$types = str_repeat('s', count($values));
Expand All @@ -235,6 +212,6 @@ private function bindUntypedValues(array $values)
$params[] =& $v;
}

return $this->_stmt->bind_param($types, ...$params);
return $this->stmt->bind_param($types, ...$params);
}
}