Skip to content

Commit

Permalink
Add SmallFloat type (#6471)
Browse files Browse the repository at this point in the history
<!-- Fill in the relevant information below to help triage your pull
request. -->

|      Q       |   A
|------------- | -----------
| Type         | feature

#### Summary

Recreated PR #6467 for branch 4.1.

This PR adds support for the `REAL` type for all DBMS, thereby resolving
issues with partial support and potential bugs related to the `REAL`
type in SQL schemas during migration creation. I've tried to explain
this issue in detail through the `INET` type here
#6466.

Checked DBMS:

- [x] PostgreSQL (represents `REAL` as `float4` or `real`)
- [x] MySQL/MariaDB
(#6467 (comment))
- [x] MSSQL (represents `REAL` as `real`)
- [x] Oracle (represents `REAL` as `float(63)`) [doc
](https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlqr/Data-Types.html)
- [x] IBM DB2 (represents `REAL` as `real`)
- [x] SQLite (represents `REAL` as `real`)
  • Loading branch information
berkut1 authored Jul 22, 2024
1 parent 083647a commit 6ebcb77
Show file tree
Hide file tree
Showing 22 changed files with 199 additions and 19 deletions.
26 changes: 22 additions & 4 deletions docs/en/reference/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,21 @@ or ``null`` if no data is present.
it approximates precision which can lead to false assumptions in
applications.

smallfloat
++++++++++

Maps and converts single precision floating-point values.
This type is suitable for storing numeric data with approximate precision, where 4-byte (32-bit) storage is sufficient.
Single precision values typically have a wide range, accommodating most numerical requirements with a precision of up to 7 decimal digits.
Values retrieved from the database are always converted to PHP's ``float``/``double`` type or ``null`` if no data is present.

float
+++++

Maps and converts numeric data with floating-point precision.
If you only need an approximate precision for numbers with fractions, you should
consider using this type.
Values retrieved from the database are always converted to PHP's
Maps and converts double precision floating-point values.
This type is suitable for storing numeric data with higher precision, requiring 8-byte (64-bit) storage.
Double precision values typically offer an extensive range, meeting the demands of more precise calculations
with a precision of up to 15 decimal digits. Values retrieved from the database are always converted to PHP's
``float``/``double`` type or ``null`` if no data is present.

String types
Expand Down Expand Up @@ -572,6 +580,16 @@ Please also notice the mapping specific footnotes for additional information.
| | +--------------------------+ | |
| | | **SQLite** | | |
+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+
| **smallfloat** | ``float`` | **MySQL** | *all* | ``FLOAT`` ``UNSIGNED`` [10] |
| | +--------------------------+---------+----------------------------------------------------------+
| | | **PostgreSQL** | *all* | ``REAL`` |
| | +--------------------------+ | |
| | | **Oracle** | | |
| | +--------------------------+ | |
| | | **SQL Server** | | |
| | +--------------------------+ | |
| | | **SQLite** | | |
+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+
| **float** | ``float`` | **MySQL** | *all* | ``DOUBLE PRECISION`` ``UNSIGNED`` [10] |
| | +--------------------------+---------+----------------------------------------------------------+
| | | **PostgreSQL** | *all* | ``DOUBLE PRECISION`` |
Expand Down
10 changes: 9 additions & 1 deletion src/Platforms/AbstractMySQLPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,14 @@ public function getFloatDeclarationSQL(array $column): string
return 'DOUBLE PRECISION' . $this->getUnsignedDeclaration($column);
}

/**
* {@inheritDoc}
*/
public function getSmallFloatDeclarationSQL(array $column): string
{
return 'FLOAT' . $this->getUnsignedDeclaration($column);
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -727,7 +735,7 @@ protected function initializeDoctrineTypeMappings(): void
'datetime' => Types::DATETIME_MUTABLE,
'decimal' => Types::DECIMAL,
'double' => Types::FLOAT,
'float' => Types::FLOAT,
'float' => Types::SMALLFLOAT,
'int' => Types::INTEGER,
'integer' => Types::INTEGER,
'json' => Types::JSON,
Expand Down
6 changes: 6 additions & 0 deletions src/Platforms/AbstractPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -1877,6 +1877,12 @@ public function getFloatDeclarationSQL(array $column): string
return 'DOUBLE PRECISION';
}

/** @param mixed[] $column */
public function getSmallFloatDeclarationSQL(array $column): string
{
return 'REAL';
}

/**
* Gets the default transaction isolation level of the platform.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Platforms/DB2Platform.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected function initializeDoctrineTypeMappings(): void
'decimal' => Types::DECIMAL,
'double' => Types::FLOAT,
'integer' => Types::INTEGER,
'real' => Types::FLOAT,
'real' => Types::SMALLFLOAT,
'smallint' => Types::SMALLINT,
'time' => Types::TIME_MUTABLE,
'timestamp' => Types::DATETIME_MUTABLE,
Expand Down
1 change: 1 addition & 0 deletions src/Platforms/OraclePlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ protected function initializeDoctrineTypeMappings(): void
'nvarchar2' => Types::STRING,
'pls_integer' => Types::BOOLEAN,
'raw' => Types::BINARY,
'real' => Types::SMALLFLOAT,
'rowid' => Types::STRING,
'timestamp' => Types::DATETIME_MUTABLE,
'timestamptz' => Types::DATETIMETZ_MUTABLE,
Expand Down
4 changes: 2 additions & 2 deletions src/Platforms/PostgreSQLPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ protected function initializeDoctrineTypeMappings(): void
'double' => Types::FLOAT,
'double precision' => Types::FLOAT,
'float' => Types::FLOAT,
'float4' => Types::FLOAT,
'float4' => Types::SMALLFLOAT,
'float8' => Types::FLOAT,
'inet' => Types::STRING,
'int' => Types::INTEGER,
Expand All @@ -717,7 +717,7 @@ protected function initializeDoctrineTypeMappings(): void
'serial' => Types::INTEGER,
'serial4' => Types::INTEGER,
'serial8' => Types::BIGINT,
'real' => Types::FLOAT,
'real' => Types::SMALLFLOAT,
'smallint' => Types::SMALLINT,
'text' => Types::TEXT,
'time' => Types::TIME_MUTABLE,
Expand Down
2 changes: 1 addition & 1 deletion src/Platforms/SQLServerPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ protected function initializeDoctrineTypeMappings(): void
'ntext' => Types::TEXT,
'numeric' => Types::DECIMAL,
'nvarchar' => Types::STRING,
'real' => Types::FLOAT,
'real' => Types::SMALLFLOAT,
'smalldatetime' => Types::DATETIME_MUTABLE,
'smallint' => Types::SMALLINT,
'smallmoney' => Types::INTEGER,
Expand Down
2 changes: 1 addition & 1 deletion src/Platforms/SQLitePlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ protected function initializeDoctrineTypeMappings(): void
'ntext' => 'string',
'numeric' => 'decimal',
'nvarchar' => 'string',
'real' => 'float',
'real' => 'smallfloat',
'serial' => 'integer',
'smallint' => 'smallint',
'string' => 'string',
Expand Down
7 changes: 7 additions & 0 deletions src/Schema/OracleSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ protected function _getPortableTableColumnDefinition(array $tableColumn): Column

break;

case 'float':
if ($precision === 63) {
$type = 'smallfloat';
}

break;

case 'varchar':
case 'varchar2':
case 'nvarchar2':
Expand Down
30 changes: 30 additions & 0 deletions src/Types/SmallFloatType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Types;

use Doctrine\DBAL\Platforms\AbstractPlatform;

class SmallFloatType extends Type
{
/**
* {@inheritDoc}
*/
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
return $platform->getSmallFloatDeclarationSQL($column);
}

/**
* @param T $value
*
* @return (T is null ? null : float)
*
* @template T
*/
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?float
{
return $value === null ? null : (float) $value;
}
}
1 change: 1 addition & 0 deletions src/Types/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ abstract class Type
Types::INTEGER => IntegerType::class,
Types::JSON => JsonType::class,
Types::SIMPLE_ARRAY => SimpleArrayType::class,
Types::SMALLFLOAT => SmallFloatType::class,
Types::SMALLINT => SmallIntType::class,
Types::STRING => StringType::class,
Types::TEXT => TextType::class,
Expand Down
1 change: 1 addition & 0 deletions src/Types/Types.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ final class Types
public const INTEGER = 'integer';
public const JSON = 'json';
public const SIMPLE_ARRAY = 'simple_array';
public const SMALLFLOAT = 'smallfloat';
public const SMALLINT = 'smallint';
public const STRING = 'string';
public const TEXT = 'text';
Expand Down
6 changes: 4 additions & 2 deletions tests/Functional/Driver/PgSQL/ResultTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,10 @@ public static function typedValueProvider(): Generator
yield 'text' => ['TEXT', 'some value', Types::STRING];
yield 'boolean true' => ['BOOLEAN', true, Types::BOOLEAN];
yield 'boolean false' => ['BOOLEAN', false, Types::BOOLEAN];
yield 'float' => ['REAL', 47.11, Types::FLOAT];
yield 'negative float with exponent' => ['REAL', -8.15e10, Types::FLOAT];
yield 'float' => ['DOUBLE PRECISION', 47.11, Types::FLOAT];
yield 'real' => ['REAL', 47.11, Types::SMALLFLOAT];
yield 'negative float with exponent' => ['DOUBLE PRECISION', -8.15e10, Types::FLOAT];
yield 'negative real with exponent' => ['REAL', -8.15e5, Types::SMALLFLOAT];
yield 'double' => ['DOUBLE PRECISION', 47.11, Types::FLOAT];
yield 'decimal' => ['NUMERIC (6, 2)', '47.11', Types::DECIMAL];
yield 'binary' => ['BYTEA', chr(0x8b), Types::BINARY];
Expand Down
14 changes: 8 additions & 6 deletions tests/Functional/Schema/MySQLSchemaManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
use Doctrine\DBAL\Tests\Functional\Schema\MySQL\PointType;
use Doctrine\DBAL\Tests\TestUtil;
use Doctrine\DBAL\Types\BlobType;
use Doctrine\DBAL\Types\FloatType;
use Doctrine\DBAL\Types\JsonType;
use Doctrine\DBAL\Types\SmallFloatType;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\Types;

Expand Down Expand Up @@ -370,22 +372,22 @@ public function testListDecimalTypeColumns(): void
self::assertTrue($columns['col_unsigned']->getUnsigned());
}

public function testListFloatTypeColumns(): void
public function testListUnsignedFloatTypeColumns(): void
{
$tableName = 'test_list_float_columns';
$tableName = 'test_unsigned_float_columns';
$table = new Table($tableName);

$table->addColumn('col', Types::FLOAT);
$table->addColumn('col_unsigned', Types::FLOAT, ['unsigned' => true]);
$table->addColumn('col_smallfloat_unsigned', Types::SMALLFLOAT, ['unsigned' => true]);

$this->dropAndCreateTable($table);

$columns = $this->schemaManager->listTableColumns($tableName);

self::assertArrayHasKey('col', $columns);
self::assertArrayHasKey('col_unsigned', $columns);
self::assertFalse($columns['col']->getUnsigned());
self::assertInstanceOf(FloatType::class, $columns['col_unsigned']->getType());
self::assertInstanceOf(SmallFloatType::class, $columns['col_smallfloat_unsigned']->getType());
self::assertTrue($columns['col_unsigned']->getUnsigned());
self::assertTrue($columns['col_smallfloat_unsigned']->getUnsigned());
}

public function testJsonColumnType(): void
Expand Down
2 changes: 2 additions & 0 deletions tests/Functional/Schema/PostgreSQLSchemaManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ public function testListNegativeColumnDefaultValue(): void
$table->addColumn('col_integer', Types::INTEGER, ['default' => -1]);
$table->addColumn('col_bigint', Types::BIGINT, ['default' => -1]);
$table->addColumn('col_float', Types::FLOAT, ['default' => -1.1]);
$table->addColumn('col_smallfloat', Types::SMALLFLOAT, ['default' => -1.1]);
$table->addColumn('col_decimal', Types::DECIMAL, [
'precision' => 2,
'scale' => 1,
Expand All @@ -430,6 +431,7 @@ public function testListNegativeColumnDefaultValue(): void
self::assertEquals(-1, $columns['col_integer']->getDefault());
self::assertEquals(-1, $columns['col_bigint']->getDefault());
self::assertEquals(-1.1, $columns['col_float']->getDefault());
self::assertEquals(-1.1, $columns['col_smallfloat']->getDefault());
self::assertEquals(-1.1, $columns['col_decimal']->getDefault());
self::assertEquals('(-1)', $columns['col_string']->getDefault());
}
Expand Down
20 changes: 20 additions & 0 deletions tests/Functional/Schema/SchemaManagerFunctionalTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
use Doctrine\DBAL\Types\DateTimeType;
use Doctrine\DBAL\Types\DateType;
use Doctrine\DBAL\Types\DecimalType;
use Doctrine\DBAL\Types\FloatType;
use Doctrine\DBAL\Types\IntegerType;
use Doctrine\DBAL\Types\SmallFloatType;
use Doctrine\DBAL\Types\StringType;
use Doctrine\DBAL\Types\TextType;
use Doctrine\DBAL\Types\TimeType;
Expand Down Expand Up @@ -859,6 +861,24 @@ public function testListTableWithBlob(): void
self::assertInstanceOf(BlobType::class, $created->getColumn('binarydata')->getType());
}

public function testListTableFloatTypeColumns(): void
{
$tableName = 'test_float_columns';
$table = new Table($tableName);

$table->addColumn('col_float', Types::FLOAT);
$table->addColumn('col_smallfloat', Types::SMALLFLOAT);

$this->dropAndCreateTable($table);

$columns = $this->schemaManager->listTableColumns($tableName);

self::assertInstanceOf(FloatType::class, $columns['col_float']->getType());
self::assertInstanceOf(SmallFloatType::class, $columns['col_smallfloat']->getType());
self::assertFalse($columns['col_float']->getUnsigned());
self::assertFalse($columns['col_smallfloat']->getUnsigned());
}

/** @param mixed[] $data */
protected function createTestTable(string $name = 'test_table', array $data = []): Table
{
Expand Down
2 changes: 2 additions & 0 deletions tests/Functional/TypeConversionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ protected function setUp(): void
$table->addColumn('test_text', Types::TEXT, ['notnull' => false]);
$table->addColumn('test_json', Types::JSON, ['notnull' => false]);
$table->addColumn('test_float', Types::FLOAT, ['notnull' => false]);
$table->addColumn('test_smallfloat', Types::SMALLFLOAT, ['notnull' => false]);
$table->addColumn('test_decimal', Types::DECIMAL, ['notnull' => false, 'scale' => 2, 'precision' => 10]);
$table->setPrimaryKey(['id']);

Expand Down Expand Up @@ -91,6 +92,7 @@ public static function floatProvider(): iterable
{
return [
'float' => [Types::FLOAT, 1.5],
'smallfloat' => [Types::SMALLFLOAT, 1.5],
];
}

Expand Down
15 changes: 15 additions & 0 deletions tests/Platforms/AbstractMySQLPlatformTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,21 @@ public static function getGeneratesFloatDeclarationSQL(): iterable
];
}

/**
* {@inheritDoc}
*/
public static function getGeneratesSmallFloatDeclarationSQL(): iterable
{
return [
[[], 'FLOAT'],
[['unsigned' => true], 'FLOAT UNSIGNED'],
[['unsigned' => false], 'FLOAT'],
[['precision' => 5], 'FLOAT'],
[['scale' => 5], 'FLOAT'],
[['precision' => 4, 'scale' => 2], 'FLOAT'],
];
}

public function testQuotesDatabaseNameInListViewsSQL(): void
{
self::assertStringContainsStringIgnoringCase(
Expand Down
20 changes: 20 additions & 0 deletions tests/Platforms/AbstractPlatformTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,26 @@ public static function getGeneratesFloatDeclarationSQL(): iterable
];
}

/** @param mixed[] $column */
#[DataProvider('getGeneratesSmallFloatDeclarationSQL')]
public function testGeneratesSmallFloatDeclarationSQL(array $column, string $expectedSql): void
{
self::assertSame($expectedSql, $this->platform->getSmallFloatDeclarationSQL($column));
}

/** @return mixed[][] */
public static function getGeneratesSmallFloatDeclarationSQL(): iterable
{
return [
[[], 'REAL'],
[['unsigned' => true], 'REAL'],
[['unsigned' => false], 'REAL'],
[['precision' => 5], 'REAL'],
[['scale' => 5], 'REAL'],
[['precision' => 4, 'scale' => 2], 'REAL'],
];
}

public function testItEscapesStringsForLike(): void
{
self::assertSame(
Expand Down
3 changes: 3 additions & 0 deletions tests/Platforms/OraclePlatformTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ public function testInitializesDoctrineTypeMappings(): void

self::assertTrue($this->platform->hasDoctrineTypeMappingFor('date'));
self::assertSame(Types::DATE_MUTABLE, $this->platform->getDoctrineTypeMapping('date'));

self::assertTrue($this->platform->hasDoctrineTypeMappingFor('real'));
self::assertSame(Types::SMALLFLOAT, $this->platform->getDoctrineTypeMapping('real'));
}

public function testGetVariableLengthStringTypeDeclarationSQLNoLength(): void
Expand Down
2 changes: 1 addition & 1 deletion tests/Platforms/SQLServerPlatformTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ public function testInitializesDoctrineTypeMappings(): void
self::assertSame(Types::FLOAT, $this->platform->getDoctrineTypeMapping('float'));

self::assertTrue($this->platform->hasDoctrineTypeMappingFor('real'));
self::assertSame(Types::FLOAT, $this->platform->getDoctrineTypeMapping('real'));
self::assertSame(Types::SMALLFLOAT, $this->platform->getDoctrineTypeMapping('real'));

self::assertTrue($this->platform->hasDoctrineTypeMappingFor('double'));
self::assertSame(Types::FLOAT, $this->platform->getDoctrineTypeMapping('double'));
Expand Down
Loading

0 comments on commit 6ebcb77

Please sign in to comment.