From 3593ecbb0dfaa549a02bd4af204bcdce24c052f4 Mon Sep 17 00:00:00 2001 From: "Matthew J. Mucklo" Date: Sun, 18 Aug 2019 00:05:21 -0700 Subject: [PATCH] Issue #3631 - fix for Double data type when using MySQLi with languages that do not use '.' for the decimal point --- .travis.yml | 1 + .../DBAL/Driver/Mysqli/MysqliStatement.php | 1 + 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 | 123 ++++++++++++++++++ .../Functional/Types/LanguageDoubleTest.php | 17 +++ tests/travis/install-language-de.sh | 8 ++ 8 files changed, 165 insertions(+) create mode 100644 tests/Doctrine/Tests/DBAL/Functional/Types/DoubleTest.php create mode 100644 tests/Doctrine/Tests/DBAL/Functional/Types/LanguageDoubleTest.php create mode 100755 tests/travis/install-language-de.sh diff --git a/.travis.yml b/.travis.yml index e0d87665991..8269a7d2ab6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ before_install: before_script: - if [[ "$DB" == "mysql" || "$DB" == "mysqli" || "$DB" == *"mariadb"* ]]; then mysql < tests/travis/create-mysql-schema.sql; fi; + - tests/travis/install-language-de.sh install: - rm composer.lock diff --git a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php index 43d70853ef5..87946c9fddc 100644 --- a/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php +++ b/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -34,6 +34,7 @@ class MysqliStatement implements IteratorAggregate, Statement ParameterType::NULL => 's', ParameterType::INTEGER => 'i', ParameterType::LARGE_OBJECT => 'b', + ParameterType::DOUBLE => 'd', ]; /** @var mysqli */ diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index 5be4f2c046d..facfa157c04 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -26,6 +26,7 @@ class PDOStatement extends \PDOStatement implements Statement ParameterType::BINARY => 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 422fee895ee..53ba350c7f8 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 4988d7253dc..f11a0a04f08 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 00000000000..4ad7c4ed99f --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Types/DoubleTest.php @@ -0,0 +1,123 @@ +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); + + $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 = floatval($result1); + $result2 = floatval($result2); + $result3 = floatval($result3); + } + + if ($result1 === false) { + $this->fail('Expected $result1 to not be false'); + + return; + } + if ($result2 === false) { + $this->fail('Expected $result2 to not be false'); + + return; + } + if ($result3 === false) { + $this->fail('Expected $result3 to not be false'); + + return; + } + + $diff1 = abs($result1 - $value1); + $diff2 = abs($result2 - $value2); + $diff3 = abs($result3 - $value3); + + $this->assertLessThanOrEqual(0.0001, $diff1, sprintf('%f, %f, %f', $diff1, $result1, $value1)); + $this->assertLessThanOrEqual(0.0001, $diff2, sprintf('%f, %f, %f', $diff2, $result2, $value2)); + $this->assertLessThanOrEqual(0.0001, $diff3, sprintf('%f, %f, %f', $diff3, $result3, $value3)); + + $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/Doctrine/Tests/DBAL/Functional/Types/LanguageDoubleTest.php b/tests/Doctrine/Tests/DBAL/Functional/Types/LanguageDoubleTest.php new file mode 100644 index 00000000000..bbcced29843 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Functional/Types/LanguageDoubleTest.php @@ -0,0 +1,17 @@ +