PHPStan Level 7

parent 30b9231c
......@@ -459,11 +459,11 @@ class Connection implements DriverConnection
*/
private function getServerVersion()
{
$connection = $this->getWrappedConnection();
// Automatic platform version detection.
if ($this->_conn instanceof ServerInfoAwareConnection &&
! $this->_conn->requiresQueryForServerVersion()
) {
return $this->_conn->getServerVersion();
if ($connection instanceof ServerInfoAwareConnection && ! $connection->requiresQueryForServerVersion()) {
return $connection->getServerVersion();
}
// Unable to detect platform version.
......@@ -810,20 +810,15 @@ class Connection implements DriverConnection
}
/**
* Quotes a given input parameter.
*
* @param mixed $input The parameter to be quoted.
* @param int|null $type The type of the parameter.
*
* @return string The quoted parameter.
* {@inheritDoc}
*/
public function quote($input, $type = null)
{
$this->connect();
$connection = $this->getWrappedConnection();
[$value, $bindingType] = $this->getBindingInfo($input, $type);
return $this->_conn->quote($value, $bindingType);
return $connection->quote($value, $bindingType);
}
/**
......@@ -883,7 +878,7 @@ class Connection implements DriverConnection
return $this->executeCacheQuery($query, $params, $types, $qcp);
}
$this->connect();
$connection = $this->getWrappedConnection();
$logger = $this->_config->getSQLLogger();
if ($logger) {
......@@ -894,7 +889,7 @@ class Connection implements DriverConnection
if ($params) {
[$query, $params, $types] = SQLParserUtils::expandListParameters($query, $params, $types);
$stmt = $this->_conn->prepare($query);
$stmt = $connection->prepare($query);
if ($types) {
$this->_bindTypedValues($stmt, $params, $types);
$stmt->execute();
......@@ -902,7 +897,7 @@ class Connection implements DriverConnection
$stmt->execute($params);
}
} else {
$stmt = $this->_conn->query($query);
$stmt = $connection->query($query);
}
} catch (Throwable $ex) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $query, $this->resolveParams($params, $types));
......@@ -931,8 +926,9 @@ class Connection implements DriverConnection
*/
public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qcp)
{
$resultCache = $qcp->getResultCacheDriver() ?: $this->_config->getResultCacheImpl();
if (! $resultCache) {
$resultCache = $qcp->getResultCacheDriver() ?? $this->_config->getResultCacheImpl();
if ($resultCache === null) {
throw CacheException::noResultDriverConfigured();
}
......@@ -994,7 +990,7 @@ class Connection implements DriverConnection
*/
public function query()
{
$this->connect();
$connection = $this->getWrappedConnection();
$args = func_get_args();
......@@ -1004,7 +1000,7 @@ class Connection implements DriverConnection
}
try {
$statement = $this->_conn->query(...$args);
$statement = $connection->query(...$args);
} catch (Throwable $ex) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $args[0]);
}
......@@ -1034,7 +1030,7 @@ class Connection implements DriverConnection
*/
public function executeUpdate($query, array $params = [], array $types = [])
{
$this->connect();
$connection = $this->getWrappedConnection();
$logger = $this->_config->getSQLLogger();
if ($logger) {
......@@ -1045,7 +1041,8 @@ class Connection implements DriverConnection
if ($params) {
[$query, $params, $types] = SQLParserUtils::expandListParameters($query, $params, $types);
$stmt = $this->_conn->prepare($query);
$stmt = $connection->prepare($query);
if ($types) {
$this->_bindTypedValues($stmt, $params, $types);
$stmt->execute();
......@@ -1054,7 +1051,7 @@ class Connection implements DriverConnection
}
$result = $stmt->rowCount();
} else {
$result = $this->_conn->exec($query);
$result = $connection->exec($query);
}
} catch (Throwable $ex) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $query, $this->resolveParams($params, $types));
......@@ -1078,7 +1075,7 @@ class Connection implements DriverConnection
*/
public function exec($statement)
{
$this->connect();
$connection = $this->getWrappedConnection();
$logger = $this->_config->getSQLLogger();
if ($logger) {
......@@ -1086,7 +1083,7 @@ class Connection implements DriverConnection
}
try {
$result = $this->_conn->exec($statement);
$result = $connection->exec($statement);
} catch (Throwable $ex) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement);
}
......@@ -1115,9 +1112,7 @@ class Connection implements DriverConnection
*/
public function errorCode()
{
$this->connect();
return $this->_conn->errorCode();
return $this->getWrappedConnection()->errorCode();
}
/**
......@@ -1125,9 +1120,7 @@ class Connection implements DriverConnection
*/
public function errorInfo()
{
$this->connect();
return $this->_conn->errorInfo();
return $this->getWrappedConnection()->errorInfo();
}
/**
......@@ -1144,9 +1137,7 @@ class Connection implements DriverConnection
*/
public function lastInsertId($seqName = null)
{
$this->connect();
return $this->_conn->lastInsertId($seqName);
return $this->getWrappedConnection()->lastInsertId($seqName);
}
/**
......@@ -1228,7 +1219,7 @@ class Connection implements DriverConnection
*/
public function beginTransaction()
{
$this->connect();
$connection = $this->getWrappedConnection();
++$this->transactionNestingLevel;
......@@ -1238,7 +1229,9 @@ class Connection implements DriverConnection
if ($logger) {
$logger->startQuery('"START TRANSACTION"');
}
$this->_conn->beginTransaction();
$connection->beginTransaction();
if ($logger) {
$logger->stopQuery();
}
......@@ -1270,7 +1263,7 @@ class Connection implements DriverConnection
throw ConnectionException::commitFailedRollbackOnly();
}
$this->connect();
$connection = $this->getWrappedConnection();
$logger = $this->_config->getSQLLogger();
......@@ -1278,7 +1271,9 @@ class Connection implements DriverConnection
if ($logger) {
$logger->startQuery('"COMMIT"');
}
$this->_conn->commit();
$connection->commit();
if ($logger) {
$logger->stopQuery();
}
......@@ -1332,7 +1327,7 @@ class Connection implements DriverConnection
throw ConnectionException::noActiveTransaction();
}
$this->connect();
$connection = $this->getWrappedConnection();
$logger = $this->_config->getSQLLogger();
......@@ -1341,7 +1336,7 @@ class Connection implements DriverConnection
$logger->startQuery('"ROLLBACK"');
}
$this->transactionNestingLevel = 0;
$this->_conn->rollBack();
$connection->rollBack();
$this->isRollbackOnly = false;
if ($logger) {
$logger->stopQuery();
......@@ -1380,7 +1375,7 @@ class Connection implements DriverConnection
throw ConnectionException::savepointsNotSupported();
}
$this->_conn->exec($this->platform->createSavePoint($savepoint));
$this->getWrappedConnection()->exec($this->platform->createSavePoint($savepoint));
}
/**
......@@ -1402,7 +1397,7 @@ class Connection implements DriverConnection
return;
}
$this->_conn->exec($this->platform->releaseSavePoint($savepoint));
$this->getWrappedConnection()->exec($this->platform->releaseSavePoint($savepoint));
}
/**
......@@ -1420,17 +1415,18 @@ class Connection implements DriverConnection
throw ConnectionException::savepointsNotSupported();
}
$this->_conn->exec($this->platform->rollbackSavePoint($savepoint));
$this->getWrappedConnection()->exec($this->platform->rollbackSavePoint($savepoint));
}
/**
* Gets the wrapped driver connection.
*
* @return \Doctrine\DBAL\Driver\Connection
* @return DriverConnection
*/
public function getWrappedConnection()
{
$this->connect();
assert($this->_conn instanceof DriverConnection);
return $this->_conn;
}
......@@ -1559,7 +1555,7 @@ class Connection implements DriverConnection
* Gets the binding type of a given type. The given type can be a PDO or DBAL mapping type.
*
* @param mixed $value The value to bind.
* @param int|string $type The type to bind (PDO or DBAL).
* @param int|string|null $type The type to bind (PDO or DBAL).
*
* @return mixed[] [0] => the (escaped) value, [1] => the binding type.
*/
......@@ -1658,10 +1654,10 @@ class Connection implements DriverConnection
*/
public function ping()
{
$this->connect();
$connection = $this->getWrappedConnection();
if ($this->_conn instanceof PingableConnection) {
return $this->_conn->ping();
if ($connection instanceof PingableConnection) {
return $connection->ping();
}
try {
......
......@@ -11,6 +11,7 @@ use Doctrine\DBAL\Event\ConnectionEventArgs;
use Doctrine\DBAL\Events;
use InvalidArgumentException;
use function array_rand;
use function assert;
use function count;
use function func_get_args;
......@@ -344,6 +345,7 @@ class MasterSlaveConnection extends Connection
public function query()
{
$this->connect('master');
assert($this->_conn instanceof DriverConnection);
$args = func_get_args();
......
......@@ -17,8 +17,8 @@ use function is_object;
use function is_resource;
use function is_string;
use function json_encode;
use function preg_replace;
use function sprintf;
use function str_split;
class DBALException extends Exception
{
......@@ -186,7 +186,7 @@ class DBALException extends Exception
if (! is_string($json) || $json === 'null' && is_string($param)) {
// JSON encoding failed, this is not a UTF-8 string.
return '"\x' . implode('\x', str_split(bin2hex($param), 2)) . '"';
return sprintf('"%s"', preg_replace('/.{2}/', '\\x$0', bin2hex($param)));
}
return $json;
......
......@@ -34,7 +34,7 @@ class DB2Driver extends AbstractDB2Driver
$password = null;
}
return new DB2Connection($params, $username, $password, $driverOptions);
return new DB2Connection($params, (string) $username, (string) $password, $driverOptions);
}
/**
......
......@@ -13,7 +13,7 @@ class Driver extends AbstractMySQLDriver
public function connect(array $params, $username = null, $password = null, array $driverOptions = [])
{
try {
return new MysqliConnection($params, $username, $password, $driverOptions);
return new MysqliConnection($params, (string) $username, (string) $password, $driverOptions);
} catch (MysqliException $e) {
throw DBALException::driverException($this, $e);
}
......
......@@ -45,8 +45,8 @@ class MysqliStatement implements IteratorAggregate, Statement
/** @var string[]|false|null */
protected $_columnNames;
/** @var mixed[]|null */
protected $_rowBindedValues;
/** @var mixed[] */
protected $_rowBindedValues = [];
/** @var mixed[] */
protected $_bindedValues;
......@@ -318,6 +318,7 @@ class MysqliStatement implements IteratorAggregate, Statement
}
$values = $this->_fetch();
if ($values === null) {
return false;
}
......
......@@ -18,10 +18,10 @@ class Driver extends AbstractOracleDriver
{
try {
return new OCI8Connection(
$username,
$password,
(string) $username,
(string) $password,
$this->_constructDsn($params),
$params['charset'] ?? null,
$params['charset'] ?? '',
$params['sessionMode'] ?? OCI_DEFAULT,
$params['persistent'] ?? false
);
......
......@@ -10,8 +10,6 @@ use const OCI_COMMIT_ON_SUCCESS;
use const OCI_DEFAULT;
use const OCI_NO_AUTO_COMMIT;
use function addcslashes;
use function define;
use function defined;
use function func_get_args;
use function is_float;
use function is_int;
......@@ -42,18 +40,20 @@ class OCI8Connection implements Connection, ServerInfoAwareConnection
* @param string $username
* @param string $password
* @param string $db
* @param string|null $charset
* @param string $charset
* @param int $sessionMode
* @param bool $persistent
*
* @throws OCI8Exception
*/
public function __construct($username, $password, $db, $charset = null, $sessionMode = OCI_DEFAULT, $persistent = false)
{
if (! defined('OCI_NO_AUTO_COMMIT')) {
define('OCI_NO_AUTO_COMMIT', 0);
}
public function __construct(
$username,
$password,
$db,
$charset = '',
$sessionMode = OCI_DEFAULT,
$persistent = false
) {
$dbh = $persistent
? @oci_pconnect($username, $password, $db, $charset, $sessionMode)
: @oci_connect($username, $password, $db, $charset, $sessionMode);
......
......@@ -215,8 +215,7 @@ class OCI8Statement implements IteratorAggregate, Statement
*
* @param string $statement The SQL statement to parse
* @param string $tokenOffset The offset to start searching from
* @param string|null $currentLiteralDelimiter The delimiter of the current string literal
* or NULL if not currently in a literal
* @param string $currentLiteralDelimiter The delimiter of the current string literal
*
* @return bool Whether the token was found
*/
......@@ -274,7 +273,7 @@ class OCI8Statement implements IteratorAggregate, Statement
*/
public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null)
{
$column = $this->_paramMap[$column] ?? $column;
$column = $this->_paramMap[$column];
if ($type === ParameterType::LARGE_OBJECT) {
$lob = oci_new_descriptor($this->_dbh, OCI_D_LOB);
......
......@@ -24,7 +24,7 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
public function __construct($dsn, $user = null, $password = null, ?array $options = null)
{
try {
parent::__construct($dsn, $user, $password, $options);
parent::__construct($dsn, (string) $user, (string) $password, (array) $options);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDOStatement::class, []]);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $exception) {
......@@ -95,6 +95,10 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
public function lastInsertId($name = null)
{
try {
if ($name === null) {
return parent::lastInsertId();
}
return parent::lastInsertId($name);
} catch (\PDOException $exception) {
throw new PDOException($exception);
......
......@@ -6,7 +6,9 @@ use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType;
use PDO;
use const E_USER_DEPRECATED;
use function array_slice;
use function assert;
use function func_get_args;
use function is_array;
use function sprintf;
use function trigger_error;
......@@ -90,7 +92,7 @@ class PDOStatement extends \PDOStatement implements Statement
$type = $this->convertParamType($type);
try {
return parent::bindParam($column, $variable, $type, $length, $driverOptions);
return parent::bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3));
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
......@@ -127,22 +129,14 @@ class PDOStatement extends \PDOStatement implements Statement
*/
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
{
$fetchMode = $this->convertFetchMode($fetchMode);
try {
if ($fetchMode === null && $cursorOrientation === PDO::FETCH_ORI_NEXT && $cursorOffset === 0) {
return parent::fetch();
}
if ($cursorOrientation === PDO::FETCH_ORI_NEXT && $cursorOffset === 0) {
return parent::fetch($fetchMode);
}
$args = func_get_args();
if ($cursorOffset === 0) {
return parent::fetch($fetchMode, $cursorOrientation);
if (isset($args[0])) {
$args[0] = $this->convertFetchMode($args[0]);
}
return parent::fetch($fetchMode, $cursorOrientation, $cursorOffset);
try {
return parent::fetch(...$args);
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
......@@ -153,7 +147,11 @@ class PDOStatement extends \PDOStatement implements Statement
*/
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
{
$fetchMode = $this->convertFetchMode($fetchMode);
$args = func_get_args();
if (isset($args[0])) {
$args[0] = $this->convertFetchMode($args[0]);
}
if ($fetchMode === null && $fetchArgument === null && $ctorArgs === null) {
$args = [];
......@@ -210,14 +208,10 @@ class PDOStatement extends \PDOStatement implements Statement
/**
* Converts DBAL fetch mode to PDO fetch mode
*
* @param int|null $fetchMode Fetch mode
* @param int $fetchMode Fetch mode
*/
private function convertFetchMode(?int $fetchMode) : ?int
private function convertFetchMode(int $fetchMode) : int
{
if ($fetchMode === null) {
return null;
}
if (! isset(self::FETCH_MODE_MAP[$fetchMode])) {
// TODO: next major: throw an exception
@trigger_error(sprintf(
......
......@@ -190,6 +190,6 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection
*/
public function errorInfo()
{
return sqlsrv_errors(SQLSRV_ERR_ERRORS);
return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS);
}
}
......@@ -16,12 +16,11 @@ class SQLSrvException extends AbstractDriverException
*/
public static function fromSqlSrvErrors()
{
$errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
$message = '';
$sqlState = null;
$errorCode = null;
foreach ($errors as $error) {
foreach ((array) sqlsrv_errors(SQLSRV_ERR_ERRORS) as $error) {
$message .= 'SQLSTATE [' . $error['SQLSTATE'] . ', ' . $error['code'] . ']: ' . $error['message'] . "\n";
if ($sqlState === null) {
......@@ -34,6 +33,7 @@ class SQLSrvException extends AbstractDriverException
$errorCode = $error['code'];
}
if (! $message) {
$message = 'SQL Server error occurred but no error message was retrieved from driver.';
}
......
......@@ -180,7 +180,7 @@ class SQLSrvStatement implements IteratorAggregate, Statement
public function closeCursor()
{
// not having the result means there's nothing to close
if (! $this->result) {
if ($this->stmt === null || ! $this->result) {
return true;
}
......@@ -226,7 +226,7 @@ class SQLSrvStatement implements IteratorAggregate, Statement
*/
public function errorInfo()
{
return sqlsrv_errors(SQLSRV_ERR_ERRORS);
return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS);
}
/**
......@@ -337,7 +337,7 @@ class SQLSrvStatement implements IteratorAggregate, Statement
{
// do not try fetching from the statement if it's not expected to contain result
// in order to prevent exceptional situation
if (! $this->result) {
if ($this->stmt === null || ! $this->result) {
return false;
}
......
......@@ -48,7 +48,7 @@ interface Statement extends ResultStatement
* this will be a parameter name of the form :name. For a prepared statement using
* question mark placeholders, this will be the 1-indexed position of the parameter.
* @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter.
* @param int|null $type Explicit data type for the parameter using the {@link \Doctrine\DBAL\ParameterType}
* @param int $type Explicit data type for the parameter using the {@link \Doctrine\DBAL\ParameterType}
* constants. To return an INOUT parameter from a stored procedure, use the bitwise
* OR operator to set the PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter.
* @param int|null $length You must specify maxlength when using an OUT bind
......
......@@ -27,12 +27,14 @@ use Doctrine\DBAL\TransactionIsolationLevel;
use Doctrine\DBAL\Types;
use Doctrine\DBAL\Types\Type;
use InvalidArgumentException;
use UnexpectedValueException;
use const E_USER_DEPRECATED;
use function addcslashes;
use function array_map;
use function array_merge;
use function array_unique;
use function array_values;
use function assert;
use function count;
use function explode;
use function func_get_arg;
......@@ -486,6 +488,8 @@ abstract class AbstractPlatform
$this->initializeCommentedDoctrineTypes();
}
assert(is_array($this->doctrineTypeComments));
return in_array($doctrineType->getName(), $this->doctrineTypeComments);
}
......@@ -502,6 +506,8 @@ abstract class AbstractPlatform
$this->initializeCommentedDoctrineTypes();
}
assert(is_array($this->doctrineTypeComments));
$this->doctrineTypeComments[] = $doctrineType instanceof Type ? $doctrineType->getName() : $doctrineType;
}
......@@ -1419,7 +1425,13 @@ abstract class AbstractPlatform
$this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs);
if ($eventArgs->isDefaultPrevented()) {
return $eventArgs->getSql();
$sql = $eventArgs->getSql();
if ($sql === null) {
throw new UnexpectedValueException('Default implementation of DROP TABLE was overridden with NULL');
}
return $sql;
}
}
......
......@@ -6,7 +6,6 @@ use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Schema\ColumnDiff;
use Doctrine\DBAL\Schema\Identifier;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types\Type;
use function array_merge;
......@@ -571,7 +570,7 @@ class DB2Platform extends AbstractPlatform
}
}
$this->gatherAlterColumnSQL($diff->fromTable, $columnDiff, $sql, $queryParts);
$this->gatherAlterColumnSQL($diff->getName($this), $columnDiff, $sql, $queryParts);
}
foreach ($diff->renamedColumns as $oldColumnName => $column) {
......@@ -622,12 +621,12 @@ class DB2Platform extends AbstractPlatform
/**
* Gathers the table alteration SQL for a given column diff.
*
* @param Table $table The table to gather the SQL for.
* @param Identifier $table The table to gather the SQL for.
* @param ColumnDiff $columnDiff The column diff to evaluate.
* @param string[] $sql The sequence of table alteration statements to fill.
* @param mixed[] $queryParts The sequence of column alteration clauses to fill.
*/
private function gatherAlterColumnSQL(Table $table, ColumnDiff $columnDiff, array &$sql, array &$queryParts)
private function gatherAlterColumnSQL(Identifier $table, ColumnDiff $columnDiff, array &$sql, array &$queryParts)
{
$alterColumnClauses = $this->getAlterColumnClausesSQL($columnDiff);
......
......@@ -47,9 +47,7 @@ class DrizzlePlatform extends AbstractPlatform
*/
public function getConcatExpression()
{
$args = func_get_args();
return 'CONCAT(' . implode(', ', (array) $args) . ')';
return 'CONCAT(' . implode(', ', func_get_args()) . ')';
}
/**
......
......@@ -23,7 +23,7 @@ use function func_get_args;
use function get_class;
use function implode;
use function is_string;
use function preg_replace;
use function preg_match;
use function sprintf;
use function strlen;
use function strpos;
......@@ -1312,9 +1312,15 @@ SQL
{
$limitOffsetClause = $this->getTopClauseSQL($limit, $offset);
return $limitOffsetClause === ''
? $query
: preg_replace('/^\s*(SELECT\s+(DISTINCT\s+)?)/i', '\1' . $limitOffsetClause . ' ', $query);
if ($limitOffsetClause === '') {
return $query;
}
if (! preg_match('/^\s*(SELECT\s+(DISTINCT\s+)?)(.*)/i', $query, $matches)) {
return $query;
}
return $matches[1] . $limitOffsetClause . ' ' . $matches[3];
}
private function getTopClauseSQL(?int $limit, ?int $offset) : string
......
......@@ -26,7 +26,6 @@ use function is_bool;
use function is_numeric;
use function is_string;
use function preg_match;
use function preg_replace;
use function sprintf;
use function str_replace;
use function stripos;
......@@ -343,7 +342,7 @@ SQL
*
* @param string $tableName The quoted table name to which the column belongs.
* @param string $columnName The quoted column name to create the comment for.
* @param string $comment The column's comment.
* @param string|null $comment The column's comment.
*
* @return string
*/
......@@ -702,7 +701,7 @@ SQL
*
* @param string $tableName The quoted table name to which the column belongs.
* @param string $columnName The quoted column name to alter the comment for.
* @param string $comment The column's comment.
* @param string|null $comment The column's comment.
*
* @return string
*/
......@@ -808,10 +807,10 @@ SQL
$level2Name = null
) {
return 'EXEC sp_addextendedproperty ' .
'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral($value) . ', ' .
'N' . $this->quoteStringLiteral($level0Type) . ', ' . $level0Name . ', ' .
'N' . $this->quoteStringLiteral($level1Type) . ', ' . $level1Name . ', ' .
'N' . $this->quoteStringLiteral($level2Type) . ', ' . $level2Name;
'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' .
'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' .
'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' .
'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name;
}
/**
......@@ -840,9 +839,9 @@ SQL
) {
return 'EXEC sp_dropextendedproperty ' .
'N' . $this->quoteStringLiteral($name) . ', ' .
'N' . $this->quoteStringLiteral($level0Type) . ', ' . $level0Name . ', ' .
'N' . $this->quoteStringLiteral($level1Type) . ', ' . $level1Name . ', ' .
'N' . $this->quoteStringLiteral($level2Type) . ', ' . $level2Name;
'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' .
'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' .
'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name;
}
/**
......@@ -872,10 +871,10 @@ SQL
$level2Name = null
) {
return 'EXEC sp_updateextendedproperty ' .
'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral($value) . ', ' .
'N' . $this->quoteStringLiteral($level0Type) . ', ' . $level0Name . ', ' .
'N' . $this->quoteStringLiteral($level1Type) . ', ' . $level1Name . ', ' .
'N' . $this->quoteStringLiteral($level2Type) . ', ' . $level2Name;
'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' .
'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' .
'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' .
'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name;
}
/**
......@@ -1279,9 +1278,11 @@ SQL
// Even if the TOP n is very large, the use of a CTE will
// allow the SQL Server query planner to optimize it so it doesn't
// actually scan the entire range covered by the TOP clause.
$selectPattern = '/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/im';
$replacePattern = sprintf('$1%s $2', $top);
$query = preg_replace($selectPattern, $replacePattern, $query);
if (! preg_match('/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/im', $query, $matches)) {
return $query;
}
$query = $matches[1] . $top . ' ' . $matches[2];
if (stristr($query, 'ORDER BY')) {
// Inner order by is not valid in SQL Server for our purposes
......
......@@ -121,9 +121,9 @@ class Connection extends \Doctrine\DBAL\Connection
*/
public function query()
{
$this->connect();
$connection = $this->getWrappedConnection();
$stmt = $this->_conn->query(...func_get_args());
$stmt = $connection->query(...func_get_args());
$stmt = new Statement($stmt, $this);
$stmt->setFetchMode($this->defaultFetchMode);
......
......@@ -84,7 +84,7 @@ abstract class AbstractAsset
* The shortest name is stripped of the default namespace. All other
* namespaced elements are returned as full-qualified names.
*
* @param string $defaultNamespaceName
* @param string|null $defaultNamespaceName
*
* @return string
*/
......
......@@ -188,7 +188,7 @@ abstract class AbstractSchemaManager
/**
* Returns true if all the given tables exist.
*
* @param string[] $tableNames
* @param string|string[] $tableNames
*
* @return bool
*/
......@@ -1098,28 +1098,32 @@ abstract class AbstractSchemaManager
* Given a table comment this method tries to extract a typehint for Doctrine Type, or returns
* the type given as default.
*
* @param string $comment
* @param string|null $comment
* @param string $currentType
*
* @return string
*/
public function extractDoctrineTypeFromComment($comment, $currentType)
{
if (preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) {
$currentType = $match[1];
if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) {
return $match[1];
}
return $currentType;
}
/**
* @param string $comment
* @param string $type
* @param string|null $comment
* @param string|null $type
*
* @return string
* @return string|null
*/
public function removeDoctrineTypeFromComment($comment, $type)
{
if ($comment === null) {
return null;
}
return str_replace('(DC2Type:' . $type . ')', '', $comment);
}
}
......@@ -356,7 +356,7 @@ class Column extends AbstractAsset
}
/**
* @param string $comment
* @param string|null $comment
*
* @return Column
*/
......
......@@ -253,6 +253,7 @@ class Comparator
// See if index has changed in table 2.
$table2Index = $index->isPrimary() ? $table2->getPrimaryKey() : $table2->getIndex($indexName);
assert($table2Index instanceof Index);
if (! $this->diffIndex($index, $table2Index)) {
continue;
......
......@@ -41,7 +41,6 @@ class DB2SchemaManager extends AbstractSchemaManager
$length = null;
$fixed = null;
$unsigned = false;
$scale = false;
$precision = false;
......@@ -80,7 +79,7 @@ class DB2SchemaManager extends AbstractSchemaManager
$options = [
'length' => $length,
'unsigned' => (bool) $unsigned,
'unsigned' => false,
'fixed' => (bool) $fixed,
'default' => $default,
'autoincrement' => (bool) $tableColumn['autoincrement'],
......
......@@ -64,7 +64,9 @@ class ForeignKeyConstraint extends AbstractAsset implements Constraint
*/
public function __construct(array $localColumnNames, $foreignTableName, array $foreignColumnNames, $name = null, array $options = [])
{
if ($name !== null) {
$this->_setName($name);
}
$this->_localColumnNames = $this->createIdentifierMap($localColumnNames);
......
......@@ -10,11 +10,9 @@ use function array_change_key_case;
use function array_shift;
use function array_values;
use function assert;
use function end;
use function explode;
use function is_string;
use function preg_match;
use function preg_replace;
use function str_replace;
use function stripslashes;
use function strpos;
......@@ -78,14 +76,6 @@ class MySqlSchemaManager extends AbstractSchemaManager
return parent::_getPortableTableIndexesList($tableIndexes, $tableName);
}
/**
* {@inheritdoc}
*/
protected function _getPortableSequenceDefinition($sequence)
{
return end($sequence);
}
/**
* {@inheritdoc}
*/
......@@ -227,15 +217,11 @@ class MySqlSchemaManager extends AbstractSchemaManager
if ($columnDefault === 'NULL' || $columnDefault === null) {
return null;
}
if ($columnDefault[0] === "'") {
return stripslashes(
str_replace(
"''",
"'",
preg_replace('/^\'(.*)\'$/', '$1', $columnDefault)
)
);
if (preg_match('/^\'(.*)\'$/', $columnDefault, $matches)) {
return stripslashes(str_replace("''", "'", $matches[1]));
}
switch ($columnDefault) {
case 'current_timestamp()':
return $platform->getCurrentTimestampSQL();
......
......@@ -6,6 +6,7 @@ use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Types\Type;
use Throwable;
use const CASE_LOWER;
use function array_change_key_case;
use function array_values;
......@@ -31,6 +32,7 @@ class OracleSchemaManager extends AbstractSchemaManager
parent::dropDatabase($database);
} catch (DBALException $exception) {
$exception = $exception->getPrevious();
assert($exception instanceof Throwable);
if (! $exception instanceof DriverException) {
throw $exception;
......
......@@ -134,8 +134,8 @@ class PostgreSqlSchemaManager extends AbstractSchemaManager
{
$onUpdate = null;
$onDelete = null;
$localColumns = null;
$foreignColumns = null;
$localColumns = [];
$foreignColumns = [];
$foreignTable = null;
if (preg_match('(ON UPDATE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match)) {
......
......@@ -6,6 +6,7 @@ use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Types\Type;
use PDOException;
use Throwable;
use function assert;
use function count;
use function in_array;
......@@ -31,6 +32,7 @@ class SQLServerSchemaManager extends AbstractSchemaManager
parent::dropDatabase($database);
} catch (DBALException $exception) {
$exception = $exception->getPrevious();
assert($exception instanceof Throwable);
if (! $exception instanceof DriverException) {
throw $exception;
......
......@@ -105,7 +105,9 @@ class Schema extends AbstractAsset
throw SchemaException::tableAlreadyExists($tableName);
}
if (! $table->isInDefaultNamespace($this->getName()) && ! $this->hasNamespace($namespaceName)) {
if ($namespaceName !== null
&& ! $table->isInDefaultNamespace($this->getName())
&& ! $this->hasNamespace($namespaceName)) {
$this->createNamespace($namespaceName);
}
......@@ -127,7 +129,9 @@ class Schema extends AbstractAsset
throw SchemaException::sequenceAlreadyExists($seqName);
}
if (! $sequence->isInDefaultNamespace($this->getName()) && ! $this->hasNamespace($namespaceName)) {
if ($namespaceName !== null
&& ! $sequence->isInDefaultNamespace($this->getName())
&& ! $this->hasNamespace($namespaceName)) {
$this->createNamespace($namespaceName);
}
......
......@@ -10,7 +10,7 @@ use function array_merge;
*/
class SchemaDiff
{
/** @var Schema */
/** @var Schema|null */
public $fromSchema;
/**
......
......@@ -104,11 +104,13 @@ class Sequence extends AbstractAsset
*/
public function isAutoIncrementsFor(Table $table)
{
if (! $table->hasPrimaryKey()) {
$primaryKey = $table->getPrimaryKey();
if ($primaryKey === null) {
return false;
}
$pkColumns = $table->getPrimaryKey()->getColumns();
$pkColumns = $primaryKey->getColumns();
if (count($pkColumns) !== 1) {
return false;
......
......@@ -87,11 +87,14 @@ class SingleDatabaseSynchronizer extends AbstractSchemaSynchronizer
}
foreach ($dropSchema->getTables() as $table) {
if (! $table->hasPrimaryKey()) {
$primaryKey = $table->getPrimaryKey();
if ($primaryKey === null) {
continue;
}
$columns = $table->getPrimaryKey()->getColumns();
$columns = $primaryKey->getColumns();
if (count($columns) > 1) {
continue;
}
......
......@@ -216,7 +216,7 @@ class Table extends AbstractAsset
if ($oldIndex->isPrimary()) {
$this->dropPrimaryKey();
return $this->setPrimaryKey($oldIndex->getColumns(), $newIndexName);
return $this->setPrimaryKey($oldIndex->getColumns(), $newIndexName ?? false);
}
unset($this->_indexes[$oldIndexName]);
......@@ -589,9 +589,11 @@ class Table extends AbstractAsset
*/
public function getColumns()
{
$primaryKey = $this->getPrimaryKey();
$primaryKeyColumns = [];
if ($this->hasPrimaryKey()) {
$primaryKeyColumns = $this->filterColumns($this->getPrimaryKey()->getColumns());
if ($primaryKey !== null) {
$primaryKeyColumns = $this->filterColumns($primaryKey->getColumns());
}
return array_merge($primaryKeyColumns, $this->getForeignKeyColumns(), $this->_columns);
......@@ -681,10 +683,13 @@ class Table extends AbstractAsset
*/
public function getPrimaryKeyColumns()
{
if (! $this->hasPrimaryKey()) {
$primaryKey = $this->getPrimaryKey();
if ($primaryKey === null) {
throw new DBALException('Table ' . $this->getName() . ' has no primary key.');
}
return $this->getPrimaryKey()->getColumns();
return $primaryKey->getColumns();
}
/**
......@@ -820,12 +825,16 @@ class Table extends AbstractAsset
*
* Trims quotes and lowercases the given identifier.
*
* @param string $identifier The identifier to normalize.
* @param string|null $identifier The identifier to normalize.
*
* @return string The normalized identifier.
*/
private function normalizeIdentifier($identifier)
{
if ($identifier === null) {
return '';
}
return $this->trimQuotes(strtolower($identifier));
}
}
......@@ -47,7 +47,7 @@ class CreateSchemaSqlCollector extends AbstractVisitor
*/
public function acceptTable(Table $table)
{
$this->createTableQueries = array_merge($this->createTableQueries, (array) $this->platform->getCreateTableSQL($table));
$this->createTableQueries = array_merge($this->createTableQueries, $this->platform->getCreateTableSQL($table));
}
/**
......
......@@ -81,7 +81,10 @@ class Graphviz extends AbstractVisitor
$label .= '<FONT COLOR="#2e3436" FACE="Helvetica" POINT-SIZE="12">' . $columnLabel . '</FONT>';
$label .= '</TD><TD BORDER="0" ALIGN="LEFT" BGCOLOR="#eeeeec"><FONT COLOR="#2e3436" FACE="Helvetica" POINT-SIZE="10">' . strtolower($column->getType()) . '</FONT></TD>';
$label .= '<TD BORDER="0" ALIGN="RIGHT" BGCOLOR="#eeeeec" PORT="col' . $column->getName() . '">';
if ($table->hasPrimaryKey() && in_array($column->getName(), $table->getPrimaryKey()->getColumns())) {
$primaryKey = $table->getPrimaryKey();
if ($primaryKey !== null && in_array($column->getName(), $primaryKey->getColumns())) {
$label .= "\xe2\x9c\xb7";
}
$label .= '</TD></TR>';
......
......@@ -53,7 +53,7 @@ class PoolingShardConnection extends Connection
/** @var DriverConnection[] */
private $activeConnections = [];
/** @var int|null */
/** @var string|int|null */
private $activeShardId;
/** @var mixed[] */
......@@ -106,7 +106,7 @@ class PoolingShardConnection extends Connection
/**
* Get active shard id.
*
* @return int
* @return string|int|null
*/
public function getActiveShardId()
{
......@@ -164,7 +164,7 @@ class PoolingShardConnection extends Connection
/**
* Connects to a given shard.
*
* @param mixed $shardId
* @param string|int|null $shardId
*
* @return bool
*
......@@ -184,15 +184,15 @@ class PoolingShardConnection extends Connection
throw new ShardingException('Cannot switch shard when transaction is active.');
}
$this->activeShardId = (int) $shardId;
$activeShardId = $this->activeShardId = (int) $shardId;
if (isset($this->activeConnections[$this->activeShardId])) {
$this->_conn = $this->activeConnections[$this->activeShardId];
if (isset($this->activeConnections[$activeShardId])) {
$this->_conn = $this->activeConnections[$activeShardId];
return false;
}
$this->_conn = $this->activeConnections[$this->activeShardId] = $this->connectTo($this->activeShardId);
$this->_conn = $this->activeConnections[$activeShardId] = $this->connectTo($activeShardId);
if ($this->_eventManager->hasListeners(Events::postConnect)) {
$eventArgs = new ConnectionEventArgs($this);
......@@ -224,7 +224,7 @@ class PoolingShardConnection extends Connection
}
/**
* @param string|null $shardId
* @param string|int|null $shardId
*
* @return bool
*/
......
parameters:
level: 6
level: 7
paths:
- %currentWorkingDirectory%/lib
autoload_files:
......@@ -12,7 +12,12 @@ parameters:
# removing it would be BC break
- '~^Constructor of class Doctrine\\DBAL\\Schema\\Table has an unused parameter \$idGeneratorType\.\z~'
# declaring $tableName in AbstractSchemaManager::_getPortableTableIndexesList() non-optional will be a BC break
- '~^Parameter #2 \$table of class Doctrine\\DBAL\\Event\\SchemaIndexDefinitionEventArgs constructor expects string, string\|null given\.\z~'
# changing these would be a BC break, to be done in next major
- "~^Casting to bool something that's already bool.~"
- "~^Casting to int something that's already int.~"
- '~^Method Doctrine\\DBAL\\Driver\\IBMDB2\\DB2Connection::exec\(\) should return int but returns bool\.\z~'
- '~^Method Doctrine\\DBAL\\Query\\QueryBuilder::execute\(\) should return Doctrine\\DBAL\\Driver\\Statement\|int but returns Doctrine\\DBAL\\Driver\\ResultStatement\.\z~'
- '~^Property Doctrine\\DBAL\\Schema\\Table::\$_primaryKeyName \(string\) does not accept (default value of type )?false\.\z~'
......@@ -33,6 +38,9 @@ parameters:
- '~^Parameter #2 \$registeredAliases of static method Doctrine\\DBAL\\Query\\QueryException::unknownAlias\(\) expects array<string>, array<int, int|string> given\.\z~'
- '~^Parameter #2 \$registeredAliases of static method Doctrine\\DBAL\\Query\\QueryException::nonUniqueAlias\(\) expects array<string>, array<int, int|string> given\.\z~'
# PHPStan is too strict about preg_replace(): https://phpstan.org/r/993dc99f-0d43-4b51-868b-d01f982c1463
- '~^Method Doctrine\\DBAL\\Platforms\\AbstractPlatform::escapeStringForLike\(\) should return string but returns string|null\.\z~'
# legacy variadic-like signature
- '~^Method Doctrine\\DBAL\\Driver\\Connection::query\(\) invoked with \d+ parameters?, 0 required\.\z~'
......
......@@ -28,7 +28,6 @@ use Doctrine\Tests\Mocks\ServerInfoAwareConnectionMock;
use Doctrine\Tests\Mocks\VersionAwarePlatformDriverMock;
use Exception;
use PHPUnit\Framework\MockObject\MockObject;
use ReflectionObject;
use stdClass;
use function call_user_func_array;
......@@ -605,29 +604,6 @@ class ConnectionTest extends DbalTestCase
self::assertSame($result, $conn->fetchColumn($statement, $params, $column, $types));
}
public function testConnectionIsClosedButNotUnset()
{
// mock Connection, and make connect() purposefully do nothing
$connection = $this->getMockBuilder(Connection::class)
->disableOriginalConstructor()
->setMethods(['connect'])
->getMock();
// artificially set the wrapped connection to non-null
$reflection = new ReflectionObject($connection);
$connProperty = $reflection->getProperty('_conn');
$connProperty->setAccessible(true);
$connProperty->setValue($connection, new stdClass());
// close the connection (should nullify the wrapped connection)
$connection->close();
// the wrapped connection should be null
// (and since connect() does nothing, this will not reconnect)
// this will also fail if this _conn property was unset instead of set to null
self::assertNull($connection->getWrappedConnection());
}
public function testFetchAll()
{
$statement = 'SELECT * FROM foo WHERE bar = ?';
......
......@@ -4,7 +4,6 @@ namespace Doctrine\Tests\DBAL\Functional;
use Doctrine\DBAL\ColumnCase;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\PDOSqlsrv\Driver;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\Portability\Connection as ConnectionPortability;
......@@ -136,29 +135,6 @@ class PortabilityTest extends DbalFunctionalTestCase
self::assertArrayNotHasKey(0, $row, 'The row should not contain numerical keys.');
}
/**
* @requires extension pdo
*/
public function testPortabilityPdoSqlServer()
{
$portability = ConnectionPortability::PORTABILITY_SQLSRV;
$params = ['portability' => $portability];
$driverMock = $this->getMockBuilder(Driver::class)
->setMethods(['connect'])
->getMock();
$driverMock->expects($this->once())
->method('connect')
->will($this->returnValue(null));
$connection = new ConnectionPortability($params, $driverMock);
$connection->connect($params);
self::assertEquals($portability, $connection->getPortability());
}
/**
* @param string $field
* @param mixed[] $expected
......
......@@ -39,11 +39,13 @@ class CreateSchemaSqlCollectorTest extends TestCase
->getMockForAbstractClass();
$this->visitor = new CreateSchemaSqlCollector($this->platformMock);
foreach (['getCreateSchemaSQL', 'getCreateTableSQL', 'getCreateForeignKeySQL', 'getCreateSequenceSQL'] as $method) {
$this->platformMock->expects($this->any())
->method($method)
->will($this->returnValue('foo'));
foreach (['getCreateSchemaSQL', 'getCreateForeignKeySQL', 'getCreateSequenceSQL'] as $method) {
$this->platformMock->method($method)
->willReturn('foo');
}
$this->platformMock->method('getCreateTableSQL')
->willReturn(['foo']);
}
public function testAcceptsNamespace()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment