From 6f1fa83340f4a8f42a99db557a811dd2f8d8e382 Mon Sep 17 00:00:00 2001 From: "Matthew J. Mucklo" Date: Sun, 4 Aug 2019 15:49:46 -0700 Subject: [PATCH] Address issue #3631 by adding support for a float datatype Also try to add a new functional test per request. In addition: - Fix IBM DB2 test issue due to untrusted update - Try to fix flakey Mysql tests --- .travis.yml | 17 +++ .../DBAL/Driver/AbstractMySQLDriver.php | 7 +- .../DBAL/Driver/Mysqli/MysqliConnection.php | 2 +- .../Mysqli/MysqliConnectionException.php | 10 ++ .../DBAL/Driver/Mysqli/MysqliStatement.php | 1 + .../DBAL/Driver/PDOConnectionException.php | 10 ++ lib/Doctrine/DBAL/Driver/PDOStatement.php | 1 + lib/Doctrine/DBAL/ParameterType.php | 5 + lib/Doctrine/DBAL/Types/FloatType.php | 9 ++ .../DBAL/Functional/Types/DoubleTest.php | 112 ++++++++++++++++++ tests/travis/install-db2-ibm_db2.sh | 1 + tests/travis/install-mysql-8.0.sh | 1 + tests/travis/setlocale-de.php | 3 + 13 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnectionException.php create mode 100644 lib/Doctrine/DBAL/Driver/PDOConnectionException.php create mode 100644 tests/Doctrine/Tests/DBAL/Functional/Types/DoubleTest.php create mode 100644 tests/travis/setlocale-de.php diff --git a/.travis.yml b/.travis.yml index e0d8766599..a59a1a9433 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,11 @@ after_script: travis_retry php ocular.phar code-coverage:upload --format=php-clover clover.xml fi +addons: + apt: + packages: + - language-pack-de + jobs: allow_failures: - php: 7.4snapshot @@ -339,3 +344,15 @@ jobs: install: - composer config minimum-stability dev - travis_retry composer update --prefer-dist + + - stage: TestIntl + php: 7.2 + env: LANGUAGE=de_DE.UTF-8 LC_ALL=de_DE.UTF-8 LANG=de_DE.UTF-8 DB=mysqli.docker MYSQL_VERSION=8.0 + sudo: required + services: + - docker + before_script: + - bash ./tests/travis/install-mysql-8.0.sh + script: + - php -d"auto_prepend_file=$PWD/tests/travis/setlocale-de.php" ./vendor/bin/phpunit --configuration tests/travis/$DB.travis.xml + diff --git a/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php b/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php index c46ddc63dd..aab5d36695 100644 --- a/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php +++ b/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php @@ -90,8 +90,13 @@ public function convertException($message, DriverException $exception) case '1429': case '2002': case '2005': + case '2054': return new Exception\ConnectionException($message, $exception); - + case '2006': + if ($exception instanceof Driver\Mysqli\MysqliConnectionException || $exception instanceof PDOConnectionException) { + return new Exception\ConnectionException($message, $exception); + } + break; case '1048': case '1121': case '1138': diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php index 1f1a1d218c..871755702e 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php @@ -68,7 +68,7 @@ public function __construct(array $params, $username, $password, array $driverOp }); try { if (! $this->conn->real_connect($params['host'], $username, $password, $dbname, $port, $socket, $flags)) { - throw new MysqliException($this->conn->connect_error, $this->conn->sqlstate ?? 'HY000', $this->conn->connect_errno); + throw new MysqliConnectionException($this->conn->connect_error, $this->conn->sqlstate ?? 'HY000', $this->conn->connect_errno); } } finally { restore_error_handler(); diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnectionException.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnectionException.php new file mode 100644 index 0000000000..bd26b739ea --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnectionException.php @@ -0,0 +1,10 @@ + 's', ParameterType::INTEGER => 'i', ParameterType::LARGE_OBJECT => 'b', + ParameterType::DOUBLE => 'd', ]; /** @var mysqli */ diff --git a/lib/Doctrine/DBAL/Driver/PDOConnectionException.php b/lib/Doctrine/DBAL/Driver/PDOConnectionException.php new file mode 100644 index 0000000000..61de97d103 --- /dev/null +++ b/lib/Doctrine/DBAL/Driver/PDOConnectionException.php @@ -0,0 +1,10 @@ + PDO::PARAM_LOB, ParameterType::LARGE_OBJECT => PDO::PARAM_LOB, ParameterType::BOOLEAN => PDO::PARAM_BOOL, + ParameterType::DOUBLE => PDO::PARAM_STR, ]; private const FETCH_MODE_MAP = [ diff --git a/lib/Doctrine/DBAL/ParameterType.php b/lib/Doctrine/DBAL/ParameterType.php index 422fee895e..53ba350c7f 100644 --- a/lib/Doctrine/DBAL/ParameterType.php +++ b/lib/Doctrine/DBAL/ParameterType.php @@ -49,6 +49,11 @@ final class ParameterType */ public const BINARY = 16; + /** + * Represents a double data type. + */ + public const DOUBLE = 17; + /** * This class cannot be instantiated. */ diff --git a/lib/Doctrine/DBAL/Types/FloatType.php b/lib/Doctrine/DBAL/Types/FloatType.php index 4988d7253d..f11a0a04f0 100644 --- a/lib/Doctrine/DBAL/Types/FloatType.php +++ b/lib/Doctrine/DBAL/Types/FloatType.php @@ -2,6 +2,7 @@ namespace Doctrine\DBAL\Types; +use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Platforms\AbstractPlatform; class FloatType extends Type @@ -29,4 +30,12 @@ public function convertToPHPValue($value, AbstractPlatform $platform) { return $value === null ? null : (float) $value; } + + /** + * {@inheritdoc} + */ + public function getBindingType() + { + return ParameterType::DOUBLE; + } } diff --git a/tests/Doctrine/Tests/DBAL/Functional/Types/DoubleTest.php b/tests/Doctrine/Tests/DBAL/Functional/Types/DoubleTest.php new file mode 100644 index 0000000000..3bb69ce80e --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Types/DoubleTest.php @@ -0,0 +1,112 @@ +addColumn('id', 'integer'); + $table->addColumn('val', 'float'); + $table->setPrimaryKey(['id']); + + $sm = $this->connection->getSchemaManager(); + $sm->dropAndCreateTable($table); + } + + public function testInsertAndSelect() : void + { + $value1 = 1.1; + $value2 = 77.99999999999; + $value3 = microtime(true); + $localeInfo = localeconv(); + + $this->insert(1, $value1); + $this->insert(2, $value2); + $this->insert(3, $value3); + + $result1 = $this->select(1); + $result2 = $this->select(2); + $result3 = $this->select(3); + + if (is_string($result1)) { + $result1 = str_replace('.', $localeInfo['decimal_point'] ?? '.', $result1); + $result2 = str_replace('.', $localeInfo['decimal_point'] ?? '.', $result2); + $result3 = str_replace('.', $localeInfo['decimal_point'] ?? '.', $result3); + $result1 = floatval($result1); + $result2 = floatval($result2); + $result3 = floatval($result3); + } + + $diff1 = abs($result1 - $value1); + $diff2 = abs($result2 - $value2); + $diff3 = abs($result3 - $value3); + + $this->assertLessThanOrEqual(0.0001, $diff1); + $this->assertLessThanOrEqual(0.0001, $diff2); + $this->assertLessThanOrEqual(0.0001, $diff3); + + $result1 = $this->selectDouble($value1); + $result2 = $this->selectDouble($value2); + $result3 = $this->selectDouble($value3); + + $this->assertSame(is_int($result1) ? 1 : '1', $result1); + $this->assertSame(is_int($result2) ? 2 : '2', $result2); + $this->assertSame(is_int($result3) ? 3 : '3', $result3); + } + + private function insert(int $id, float $value) : void + { + $result = $this->connection->insert('double_table', [ + 'id' => $id, + 'val' => $value, + ], [ + ParameterType::INTEGER, + ParameterType::DOUBLE, + ]); + + self::assertSame(1, $result); + } + + /** + * @return mixed + */ + private function select(int $id) + { + return $this->connection->fetchColumn( + 'SELECT val FROM double_table WHERE id = ?', + [$id], + 0, + [ParameterType::INTEGER] + ); + } + + /** + * @return mixed + */ + private function selectDouble(float $value) + { + return $this->connection->fetchColumn( + 'SELECT id FROM double_table WHERE val = ?', + [$value], + 0, + [ParameterType::DOUBLE] + ); + } +} diff --git a/tests/travis/install-db2-ibm_db2.sh b/tests/travis/install-db2-ibm_db2.sh index b59bb6396f..fc98805571 100644 --- a/tests/travis/install-db2-ibm_db2.sh +++ b/tests/travis/install-db2-ibm_db2.sh @@ -5,6 +5,7 @@ set -ex echo "Installing extension" ( # updating APT packages as per support recommendation + sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6B05F25D762E3157 sudo apt -y -q update sudo apt install ksh diff --git a/tests/travis/install-mysql-8.0.sh b/tests/travis/install-mysql-8.0.sh index 952a4300ba..6e0557aa03 100644 --- a/tests/travis/install-mysql-8.0.sh +++ b/tests/travis/install-mysql-8.0.sh @@ -12,6 +12,7 @@ sudo docker run \ -p 33306:3306 \ --name mysql80 \ mysql:8.0 \ + mysqld \ --default-authentication-plugin=mysql_native_password sudo docker exec -i mysql80 bash <<< 'until echo \\q | mysql doctrine_tests > /dev/null 2>&1 ; do sleep 1; done' diff --git a/tests/travis/setlocale-de.php b/tests/travis/setlocale-de.php new file mode 100644 index 0000000000..e47ee1e200 --- /dev/null +++ b/tests/travis/setlocale-de.php @@ -0,0 +1,3 @@ +