diff --git a/src/Database/Drivers/Engines/MySQLEngine.php b/src/Database/Drivers/Engines/MySQLEngine.php index ac77b9888..35806c4f6 100644 --- a/src/Database/Drivers/Engines/MySQLEngine.php +++ b/src/Database/Drivers/Engines/MySQLEngine.php @@ -176,9 +176,6 @@ public function getForeignKeys(string $table): array public function resolveColumnConverter(array $meta, TypeConverter $converter): ?\Closure { return match ($meta['nativeType']) { - 'NEWDECIMAL' => $meta['scale'] === 0 - ? $converter->toInt(...) - : $converter->toFloat(...), 'TINY' => $meta['length'] === 1 && $converter->convertBoolean ? $converter->toBool(...) : $converter->toInt(...), diff --git a/src/Database/Factory.php b/src/Database/Factory.php index 64c252c39..7fdc9db50 100644 --- a/src/Database/Factory.php +++ b/src/Database/Factory.php @@ -25,7 +25,7 @@ final class Factory 'pdo-sqlite' => Drivers\PDO\SQLite\Driver::class, 'pdo-sqlsrv' => Drivers\PDO\SQLSrv\Driver::class, ]; - private const TypeConverterOptions = ['convertBoolean', 'convertDateTime', 'newDateTime']; + private const TypeConverterOptions = ['convertBoolean', 'convertDateTime', 'convertDecimal', 'newDateTime']; /** @internal */ diff --git a/src/Database/TypeConverter.php b/src/Database/TypeConverter.php index 2fa4e4bac..8e7bd11e8 100644 --- a/src/Database/TypeConverter.php +++ b/src/Database/TypeConverter.php @@ -38,6 +38,7 @@ final class TypeConverter public bool $convertBoolean = true; public bool $convertDateTime = true; + public bool $convertDecimal = true; public bool $newDateTime = true; @@ -64,8 +65,10 @@ public function resolve(array $meta): ?\Closure { return match ($this->detectType($meta['nativeType'])) { self::Integer => $this->toInt(...), - self::Float, - self::Decimal => $this->toFloat(...), + self::Float => $this->toFloat(...), + self::Decimal => $this->convertDecimal + ? ($meta['scale'] === 0 ? $this->toInt(...) : $this->toFloat(...)) + : null, self::Boolean => $this->convertBoolean ? $this->toBool(...) : null, self::DateTime, self::Date => $this->convertDateTime ? $this->toDateTime(...) : null, self::Time => $this->convertDateTime ? $this->toTime(...) : null, @@ -75,7 +78,7 @@ public function resolve(array $meta): ?\Closure } - public function toInt(int|string $value): int|float + public function toInt(int|float|string $value): int|float|string { return is_float($tmp = $value * 1) ? $value : $tmp; } diff --git a/tests/Database/ResultSet.normalizeRow.sqlsrv.phpt b/tests/Database/ResultSet.normalizeRow.sqlsrv.phpt index 09ea94fe7..1b7b39f98 100644 --- a/tests/Database/ResultSet.normalizeRow.sqlsrv.phpt +++ b/tests/Database/ResultSet.normalizeRow.sqlsrv.phpt @@ -26,7 +26,7 @@ Assert::equal([ 'date' => new DateTime('2012-10-13 00:00:00'), 'datetime' => new DateTime('2012-10-13 10:10:10'), 'datetime2' => new DateTime('2012-10-13 10:10:10'), - 'decimal' => 1.0, + 'decimal' => 1, 'float' => 1.1, 'geography' => "\xe6\x10\x00\x00\x01\x14\x87\x16\xd9\xce\xf7\xd3G@\xd7\xa3p=\n\x97^\xc0\x87\x16\xd9\xce\xf7\xd3G@\xcb\xa1E\xb6\xf3\x95^\xc0", 'geometry' => "\x00\x00\x00\x00\x01\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00Y@\x00\x00\x00\x00\x00\x00Y@\x00\x00\x00\x00\x00\x004@\x00\x00\x00\x00\x00\x80f@\x00\x00\x00\x00\x00\x80f@\x00\x00\x00\x00\x00\x80f@\x01\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x02", @@ -35,7 +35,7 @@ Assert::equal([ 'money' => 1111.1, 'nchar' => 'a', 'ntext' => 'a', - 'numeric_10_0' => 1.0, + 'numeric_10_0' => 1, 'numeric_10_2' => 1.1, 'nvarchar' => 'a', 'real' => 1.1, @@ -59,7 +59,7 @@ Assert::equal([ 'date' => new DateTime('0001-01-01 00:00:00'), 'datetime' => new DateTime('1753-01-01 00:00:00'), 'datetime2' => new DateTime('0001-01-01 00:00:00'), - 'decimal' => 0.0, + 'decimal' => 0, 'float' => 0.5, 'geography' => null, 'geometry' => null, @@ -68,7 +68,7 @@ Assert::equal([ 'money' => 0.0, 'nchar' => ' ', 'ntext' => '', - 'numeric_10_0' => 0.0, + 'numeric_10_0' => 0, 'numeric_10_2' => 0.5, 'nvarchar' => '', 'real' => 0.0, diff --git a/tests/Database/connection.options.mysql.phpt b/tests/Database/connection.options.mysql.phpt index 390cf0462..9040f52fb 100644 --- a/tests/Database/connection.options.mysql.phpt +++ b/tests/Database/connection.options.mysql.phpt @@ -91,3 +91,37 @@ test('convertDateTime = true', function () { $field = $connection->fetchField('SELECT NOW()'); Assert::type(Nette\Database\DateTime::class, $field); }); + + +test('default convertDecimal', function () { + $connection = connectToDB(['convertDecimal' => null])->getConnection(); + Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql'); + $row = $connection->fetch('SELECT * FROM types'); + Assert::same(1, $row->decimal); + Assert::same(1.1, $row->decimal2); + + $fields = $connection->fetchFields('SELECT 10, 10.5'); + Assert::same([10, 10.5], $fields); +}); + +test('convertDecimal = false', function () { + $connection = connectToDB(['convertDecimal' => false])->getConnection(); + Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql'); + $row = $connection->fetch('SELECT * FROM types'); + Assert::same('1', $row->decimal); + Assert::same('1.10', $row->decimal2); + + $fields = $connection->fetchFields('SELECT 10, 10.5'); + Assert::same([10, '10.5'], $fields); +}); + +test('convertDecimal = true', function () { + $connection = connectToDB(['convertDecimal' => true])->getConnection(); + Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/mysql-nette_test3.sql'); + $row = $connection->fetch('SELECT * FROM types'); + Assert::same(1, $row->decimal); + Assert::same(1.1, $row->decimal2); + + $fields = $connection->fetchFields('SELECT 10, 10.5'); + Assert::same([10, 10.5], $fields); +}); diff --git a/tests/Database/connection.options.sqlsrv.phpt b/tests/Database/connection.options.sqlsrv.phpt new file mode 100644 index 000000000..e37744c6e --- /dev/null +++ b/tests/Database/connection.options.sqlsrv.phpt @@ -0,0 +1,40 @@ + null])->getConnection(); + Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql'); + $row = $connection->fetch('SELECT * FROM types'); + Assert::same(1, $row->decimal); + Assert::same(1, $row->numeric_10_0); + Assert::same(1.1, $row->numeric_10_2); +}); + +test('convertDecimal = true', function () { + $connection = connectToDB(['convertDecimal' => true])->getConnection(); + Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql'); + $row = $connection->fetch('SELECT * FROM types'); + Assert::same(1, $row->decimal); + Assert::same(1, $row->numeric_10_0); + Assert::same(1.1, $row->numeric_10_2); +}); + +test('convertDecimal = false', function () { + $connection = connectToDB(['convertDecimal' => false])->getConnection(); + Nette\Database\Helpers::loadFromFile($connection, __DIR__ . '/files/sqlsrv-nette_test3.sql'); + $row = $connection->fetch('SELECT * FROM types'); + Assert::same('1', $row->decimal); + Assert::same('1', $row->numeric_10_0); + Assert::same('1.10', $row->numeric_10_2); +});