From a103cfebd51a25508bbe667793781775209486d1 Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Mon, 9 Sep 2024 13:50:30 +0200 Subject: [PATCH 1/3] QueryResultTypeWalker: support pdo_pgsql float fetches on PHP 8.4 --- src/Type/Doctrine/Descriptors/FloatType.php | 8 +- .../Doctrine/Query/QueryResultTypeWalker.php | 38 +-- ...eryResultTypeWalkerFetchTypeMatrixTest.php | 266 ++++++++++-------- 3 files changed, 162 insertions(+), 150 deletions(-) diff --git a/src/Type/Doctrine/Descriptors/FloatType.php b/src/Type/Doctrine/Descriptors/FloatType.php index 2518e72d..e475c0a2 100644 --- a/src/Type/Doctrine/Descriptors/FloatType.php +++ b/src/Type/Doctrine/Descriptors/FloatType.php @@ -53,18 +53,12 @@ public function getDatabaseInternalTypeForDriver(Connection $connection): Type { $driverType = $this->driverDetector->detect($connection); - if ($driverType === DriverDetector::PDO_PGSQL) { - return new IntersectionType([ - new StringType(), - new AccessoryNumericStringType(), - ]); - } - if (in_array($driverType, [ DriverDetector::SQLITE3, DriverDetector::PDO_SQLITE, DriverDetector::MYSQLI, DriverDetector::PDO_MYSQL, + DriverDetector::PDO_PGSQL, DriverDetector::PGSQL, ], true)) { return new \PHPStan\Type\FloatType(); diff --git a/src/Type/Doctrine/Query/QueryResultTypeWalker.php b/src/Type/Doctrine/Query/QueryResultTypeWalker.php index 4ef105d9..54d836c6 100644 --- a/src/Type/Doctrine/Query/QueryResultTypeWalker.php +++ b/src/Type/Doctrine/Query/QueryResultTypeWalker.php @@ -471,10 +471,6 @@ public function walkFunction($function): string } if ($this->containsOnlyNumericTypes($exprTypeNoNull)) { - if ($this->driverType === DriverDetector::PDO_PGSQL) { - return $this->marshalType($this->createNumericString($nullable)); - } - return $this->marshalType($exprType); // retains underlying type } @@ -627,13 +623,7 @@ public function walkFunction($function): string $type = TypeCombinator::addNull($type); } - } elseif ($this->driverType === DriverDetector::PDO_PGSQL) { - $type = new IntersectionType([ - new StringType(), - new AccessoryNumericStringType(), - ]); - - } elseif ($this->driverType === DriverDetector::PGSQL) { + } elseif ($this->driverType === DriverDetector::PGSQL || $this->driverType === DriverDetector::PDO_PGSQL) { $castedExprType = $this->castStringLiteralForNumericExpression($exprTypeNoNull); if ($castedExprType->isInteger()->yes() || $castedExprType->isFloat()->yes()) { @@ -1771,12 +1761,6 @@ private function inferPlusMinusTimesType(array $termTypes): Type return $this->createInteger($nullable); } - if ($this->driverType === DriverDetector::PDO_PGSQL) { - if ($this->containsOnlyNumericTypes($unionWithoutNull)) { - return $this->createNumericString($nullable); - } - } - if ($this->driverType === DriverDetector::SQLITE3 || $this->driverType === DriverDetector::PDO_SQLITE) { if (!$this->containsOnlyNumericTypes(...$typesNoNull)) { return new MixedType(); @@ -1791,7 +1775,7 @@ private function inferPlusMinusTimesType(array $termTypes): Type return $this->createFloatOrInt($nullable); } - if ($this->driverType === DriverDetector::MYSQLI || $this->driverType === DriverDetector::PDO_MYSQL || $this->driverType === DriverDetector::PGSQL) { + if ($this->driverType === DriverDetector::MYSQLI || $this->driverType === DriverDetector::PDO_MYSQL || $this->driverType === DriverDetector::PGSQL || $this->driverType === DriverDetector::PDO_PGSQL) { if ($this->containsOnlyTypes($unionWithoutNull, [new IntegerType(), new FloatType()])) { return $this->createFloat($nullable); } @@ -1857,12 +1841,6 @@ private function inferDivisionType(array $termTypes): Type return new MixedType(); } - if ($this->driverType === DriverDetector::PDO_PGSQL) { - if ($this->containsOnlyTypes($unionWithoutNull, [new IntegerType(), new FloatType(), $this->createNumericString(false)])) { - return $this->createNumericString($nullable); - } - } - if ($this->driverType === DriverDetector::SQLITE3 || $this->driverType === DriverDetector::PDO_SQLITE) { if (!$this->containsOnlyNumericTypes(...$typesNoNull)) { return new MixedType(); @@ -1877,7 +1855,7 @@ private function inferDivisionType(array $termTypes): Type return $this->createFloatOrInt($nullable); } - if ($this->driverType === DriverDetector::MYSQLI || $this->driverType === DriverDetector::PDO_MYSQL || $this->driverType === DriverDetector::PGSQL) { + if ($this->driverType === DriverDetector::MYSQLI || $this->driverType === DriverDetector::PDO_MYSQL || $this->driverType === DriverDetector::PGSQL || $this->driverType === DriverDetector::PDO_PGSQL) { if ($this->containsOnlyTypes($unionWithoutNull, [new IntegerType(), new FloatType()])) { return $this->createFloat($nullable); } @@ -2100,6 +2078,9 @@ private function hasAggregateWithoutGroupBy(): bool * - pdo_sqlite: https://github.com/php/php-src/commit/438b025a28cda2935613af412fc13702883dd3a2 * - pdo_pgsql: https://github.com/php/php-src/commit/737195c3ae6ac53b9501cfc39cc80fd462909c82 * + * Notable 8.4 changes: + * - pdo_pgsql: https://github.com/php/php-src/commit/6d10a6989897e9089d62edf939344437128e93ad + * * @param IntegerType|FloatType|BooleanType $type */ private function shouldStringifyExpressions(Type $type): TrinaryLogic @@ -2144,7 +2125,14 @@ private function shouldStringifyExpressions(Type $type): TrinaryLogic } return TrinaryLogic::createNo(); + } + if ($type->isFloat()->yes()) { + if ($this->phpVersion->getVersionId() >= 80400) { + return TrinaryLogic::createFromBoolean($stringifyFetches); + } + + return TrinaryLogic::createYes(); } return TrinaryLogic::createFromBoolean($stringifyFetches); diff --git a/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php b/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php index 04fdcba8..3faae5a6 100644 --- a/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php +++ b/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php @@ -71,6 +71,7 @@ final class QueryResultTypeWalkerFetchTypeMatrixTest extends PHPStanTestCase private const STRINGIFY_NONE = 'none'; private const STRINGIFY_DEFAULT = 'default'; private const STRINGIFY_PG_BOOL = 'pg_bool'; + private const STRINGIFY_PG_FLOAT = 'pg_float'; private const CONFIG_DEFAULT = 'default'; private const CONFIG_STRINGIFY = 'pdo_stringify'; @@ -974,15 +975,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_int + t.col_float FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 9.125, 'sqliteResult' => 9.125, - 'pdoPgsqlResult' => '9.125', + 'pdoPgsqlResult' => 9.125, 'pgsqlResult' => 9.125, 'mssqlResult' => 9.125, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_int + t.col_mixed' => [ @@ -1006,15 +1007,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_bigint + t.col_float FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 2147483648.125, 'sqliteResult' => 2147483648.125, - 'pdoPgsqlResult' => '2147483648.125', + 'pdoPgsqlResult' => 2147483648.125, 'pgsqlResult' => 2147483648.125, 'mssqlResult' => 2147483648.125, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_bigint + t.col_float (int data)' => [ @@ -1022,15 +1023,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_bigint + t.col_float FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 2.0, 'sqliteResult' => 2.0, - 'pdoPgsqlResult' => '2', + 'pdoPgsqlResult' => 2.0, 'pgsqlResult' => 2.0, 'mssqlResult' => 2.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_float + t.col_float' => [ @@ -1038,15 +1039,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_float + t.col_float FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 0.25, 'sqliteResult' => 0.25, - 'pdoPgsqlResult' => '0.25', + 'pdoPgsqlResult' => 0.25, 'pgsqlResult' => 0.25, 'mssqlResult' => 0.25, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_int + t.col_decimal' => [ @@ -1086,15 +1087,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_float + t.col_decimal FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 0.225, 'sqliteResult' => 0.225, - 'pdoPgsqlResult' => '0.225', + 'pdoPgsqlResult' => 0.225, 'pgsqlResult' => 0.225, 'mssqlResult' => 0.225, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_float + t.col_decimal (int data)' => [ @@ -1102,15 +1103,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_float + t.col_decimal FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 2.0, 'sqliteResult' => 2.0, - 'pdoPgsqlResult' => '2', + 'pdoPgsqlResult' => 2.0, 'pgsqlResult' => 2.0, 'mssqlResult' => 2.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_decimal + t.col_decimal (int data)' => [ @@ -1134,15 +1135,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_int + t.col_float + t.col_decimal FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 9.225, 'sqliteResult' => 9.225, - 'pdoPgsqlResult' => '9.225', + 'pdoPgsqlResult' => 9.225, 'pgsqlResult' => 9.225, 'mssqlResult' => 9.225, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_decimal + t.col_decimal' => [ @@ -1310,15 +1311,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_int / t.col_float FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 72.0, 'sqliteResult' => 72.0, - 'pdoPgsqlResult' => '72', + 'pdoPgsqlResult' => 72.0, 'pgsqlResult' => 72.0, 'mssqlResult' => 72.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_int / t.col_float / t.col_decimal' => [ @@ -1326,15 +1327,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_int / t.col_float / t.col_decimal FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 720.0, 'sqliteResult' => 720.0, - 'pdoPgsqlResult' => '720', + 'pdoPgsqlResult' => 720.0, 'pgsqlResult' => 720.0, 'mssqlResult' => 720.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_bigint / t.col_float' => [ @@ -1342,15 +1343,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_bigint / t.col_float FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 17179869184.0, 'sqliteResult' => 17179869184.0, - 'pdoPgsqlResult' => '17179869184', + 'pdoPgsqlResult' => 17179869184.0, 'pgsqlResult' => 17179869184.0, 'mssqlResult' => 17179869184.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_float / t.col_float' => [ @@ -1358,15 +1359,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_float / t.col_float FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_int / t.col_decimal' => [ @@ -1406,15 +1407,15 @@ public static function provideCases(): iterable 'select' => 'SELECT t.col_float / t.col_decimal FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.25, 'sqliteResult' => 1.25, - 'pdoPgsqlResult' => '1.25', + 'pdoPgsqlResult' => 1.25, 'pgsqlResult' => 1.25, 'mssqlResult' => 1.25, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_decimal / t.col_decimal' => [ @@ -1961,20 +1962,36 @@ public static function provideCases(): iterable 'stringify' => self::STRINGIFY_DEFAULT, ]; + yield 'COALESCE(t.col_float, t.col_float)' => [ + 'data' => self::dataDefault(), + 'select' => 'SELECT COALESCE(t.col_float, t.col_float) FROM %s t', + 'mysql' => self::float(), + 'sqlite' => self::float(), + 'pdo_pgsql' => self::float(), + 'pgsql' => self::float(), + 'mssql' => self::mixed(), + 'mysqlResult' => 0.125, + 'sqliteResult' => 0.125, + 'pdoPgsqlResult' => 0.125, + 'pgsqlResult' => 0.125, + 'mssqlResult' => 0.125, + 'stringify' => self::STRINGIFY_PG_FLOAT, + ]; + yield 'COALESCE(t.col_float, t.col_float) + int data' => [ 'data' => self::dataAllIntLike(), 'select' => 'SELECT COALESCE(t.col_float, t.col_float) FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 't.col_decimal' => [ @@ -2046,15 +2063,15 @@ public static function provideCases(): iterable 'select' => 'SELECT AVG(t.col_float) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrNull(), - 'pdo_pgsql' => self::numericStringOrNull(), + 'pdo_pgsql' => self::floatOrNull(), 'pgsql' => self::floatOrNull(), 'mssql' => self::mixed(), 'mysqlResult' => 0.125, 'sqliteResult' => 0.125, - 'pdoPgsqlResult' => '0.125', + 'pdoPgsqlResult' => 0.125, 'pgsqlResult' => 0.125, 'mssqlResult' => 0.125, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'AVG(t.col_float) + no data' => [ @@ -2062,7 +2079,7 @@ public static function provideCases(): iterable 'select' => 'SELECT AVG(t.col_float) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrNull(), - 'pdo_pgsql' => self::numericStringOrNull(), + 'pdo_pgsql' => self::floatOrNull(), 'pgsql' => self::floatOrNull(), 'mssql' => self::mixed(), 'mysqlResult' => null, @@ -2070,7 +2087,7 @@ public static function provideCases(): iterable 'pdoPgsqlResult' => null, 'pgsqlResult' => null, 'mssqlResult' => null, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'AVG(t.col_float) + GROUP BY' => [ @@ -2078,15 +2095,15 @@ public static function provideCases(): iterable 'select' => 'SELECT AVG(t.col_float) FROM %s t GROUP BY t.col_int', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 0.125, 'sqliteResult' => 0.125, - 'pdoPgsqlResult' => '0.125', + 'pdoPgsqlResult' => 0.125, 'pgsqlResult' => 0.125, 'mssqlResult' => 0.125, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'AVG(t.col_float_nullable) + GROUP BY' => [ @@ -2094,7 +2111,7 @@ public static function provideCases(): iterable 'select' => 'SELECT AVG(t.col_float_nullable) FROM %s t GROUP BY t.col_int', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrNull(), - 'pdo_pgsql' => self::numericStringOrNull(), + 'pdo_pgsql' => self::floatOrNull(), 'pgsql' => self::floatOrNull(), 'mssql' => self::mixed(), 'mysqlResult' => null, @@ -2102,7 +2119,7 @@ public static function provideCases(): iterable 'pdoPgsqlResult' => null, 'pgsqlResult' => null, 'mssqlResult' => null, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'AVG(t.col_decimal)' => [ @@ -2350,15 +2367,15 @@ public static function provideCases(): iterable 'select' => 'SELECT SUM(t.col_float) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrNull(), - 'pdo_pgsql' => self::numericStringOrNull(), + 'pdo_pgsql' => self::floatOrNull(), 'pgsql' => self::floatOrNull(), 'mssql' => self::mixed(), 'mysqlResult' => 0.125, 'sqliteResult' => 0.125, - 'pdoPgsqlResult' => '0.125', + 'pdoPgsqlResult' => 0.125, 'pgsqlResult' => 0.125, 'mssqlResult' => 0.125, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'SUM(t.col_float) + no data' => [ @@ -2366,7 +2383,7 @@ public static function provideCases(): iterable 'select' => 'SELECT SUM(t.col_float) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrNull(), - 'pdo_pgsql' => self::numericStringOrNull(), + 'pdo_pgsql' => self::floatOrNull(), 'pgsql' => self::floatOrNull(), 'mssql' => self::mixed(), 'mysqlResult' => null, @@ -2374,7 +2391,7 @@ public static function provideCases(): iterable 'pdoPgsqlResult' => null, 'pgsqlResult' => null, 'mssqlResult' => null, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'SUM(t.col_float) + GROUP BY' => [ @@ -2382,15 +2399,15 @@ public static function provideCases(): iterable 'select' => 'SELECT SUM(t.col_float) FROM %s t GROUP BY t.col_int', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 0.125, 'sqliteResult' => 0.125, - 'pdoPgsqlResult' => '0.125', + 'pdoPgsqlResult' => 0.125, 'pgsqlResult' => 0.125, 'mssqlResult' => 0.125, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield '1 + -(CASE WHEN MIN(t.col_float) = 0 THEN SUM(t.col_float) ELSE 0 END)' => [ // agg function (causing null) deeply inside AST @@ -2398,15 +2415,15 @@ public static function provideCases(): iterable 'select' => 'SELECT 1 + -(CASE WHEN MIN(t.col_float) = 0 THEN SUM(t.col_float) ELSE 0 END) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrIntOrNull(), - 'pdo_pgsql' => self::numericStringOrNull(), + 'pdo_pgsql' => self::floatOrNull(), 'pgsql' => self::floatOrNull(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'SUM(t.col_decimal)' => [ @@ -2686,15 +2703,15 @@ public static function provideCases(): iterable 'select' => 'SELECT MAX(t.col_float) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrNull(), - 'pdo_pgsql' => self::numericStringOrNull(), + 'pdo_pgsql' => self::floatOrNull(), 'pgsql' => self::floatOrNull(), 'mssql' => self::mixed(), 'mysqlResult' => 0.125, 'sqliteResult' => 0.125, - 'pdoPgsqlResult' => '0.125', + 'pdoPgsqlResult' => 0.125, 'pgsqlResult' => 0.125, 'mssqlResult' => 0.125, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'MAX(t.col_float) + no data' => [ @@ -2702,7 +2719,7 @@ public static function provideCases(): iterable 'select' => 'SELECT MAX(t.col_float) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrNull(), - 'pdo_pgsql' => self::numericStringOrNull(), + 'pdo_pgsql' => self::floatOrNull(), 'pgsql' => self::floatOrNull(), 'mssql' => self::mixed(), 'mysqlResult' => null, @@ -2710,7 +2727,7 @@ public static function provideCases(): iterable 'pdoPgsqlResult' => null, 'pgsqlResult' => null, 'mssqlResult' => null, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'MAX(t.col_float) + GROUP BY' => [ @@ -2718,12 +2735,12 @@ public static function provideCases(): iterable 'select' => 'SELECT MAX(t.col_float) FROM %s t GROUP BY t.col_int', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 0.125, 'sqliteResult' => 0.125, - 'pdoPgsqlResult' => '0.125', + 'pdoPgsqlResult' => 0.125, 'pgsqlResult' => 0.125, 'mssqlResult' => 0.125, 'stringify' => self::STRINGIFY_DEFAULT, @@ -2958,15 +2975,15 @@ public static function provideCases(): iterable 'select' => 'SELECT ABS(t.col_float) FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 0.125, 'sqliteResult' => 0.125, - 'pdoPgsqlResult' => '0.125', + 'pdoPgsqlResult' => 0.125, 'pgsqlResult' => 0.125, 'mssqlResult' => 0.125, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'ABS(t.col_decimal)' => [ @@ -3166,15 +3183,15 @@ public static function provideCases(): iterable 'select' => "SELECT ABS('1.0') FROM %s t", 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield "ABS('1')" => [ @@ -3182,15 +3199,15 @@ public static function provideCases(): iterable 'select' => "SELECT ABS('1') FROM %s t", 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'ABS(t.col_bigint)' => [ @@ -3614,15 +3631,15 @@ public static function provideCases(): iterable 'select' => 'SELECT SQRT(t.col_float) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrNull(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'SQRT(t.col_decimal)' => [ @@ -3646,15 +3663,15 @@ public static function provideCases(): iterable 'select' => 'SELECT SQRT(t.col_int) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => self::floatOrNull(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 3.0, 'sqliteResult' => 3.0, - 'pdoPgsqlResult' => '3', + 'pdoPgsqlResult' => 3.0, 'pgsqlResult' => 3.0, 'mssqlResult' => 3.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'SQRT(t.col_mixed)' => [ @@ -3667,10 +3684,10 @@ public static function provideCases(): iterable 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'SQRT(t.col_int_nullable)' => [ @@ -3678,7 +3695,7 @@ public static function provideCases(): iterable 'select' => 'SELECT SQRT(t.col_int_nullable) FROM %s t', 'mysql' => self::floatOrNull(), 'sqlite' => PHP_VERSION_ID >= 80100 && !self::hasDbal4() ? null : self::floatOrNull(), // fails in UDF since PHP 8.1: sqrt(): Passing null to parameter #1 ($num) of type float is deprecated - 'pdo_pgsql' => self::numericStringOrNull(), + 'pdo_pgsql' => self::floatOrNull(), 'pgsql' => self::floatOrNull(), 'mssql' => self::mixed(), 'mysqlResult' => null, @@ -3686,7 +3703,7 @@ public static function provideCases(): iterable 'pdoPgsqlResult' => null, 'pgsqlResult' => null, 'mssqlResult' => null, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'SQRT(-1)' => [ @@ -3710,15 +3727,15 @@ public static function provideCases(): iterable 'select' => 'SELECT SQRT(1) FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield "SQRT('1')" => [ @@ -3726,15 +3743,15 @@ public static function provideCases(): iterable 'select' => "SELECT SQRT('1') FROM %s t", 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield "SQRT('1.0')" => [ @@ -3742,15 +3759,15 @@ public static function provideCases(): iterable 'select' => "SELECT SQRT('1.0') FROM %s t", 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield "SQRT('1e0')" => [ @@ -3758,15 +3775,15 @@ public static function provideCases(): iterable 'select' => "SELECT SQRT('1e0') FROM %s t", 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => self::float(), 'pgsql' => self::float(), 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1.0, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield "SQRT('foo')" => [ @@ -4238,15 +4255,15 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_float_nullable, 0) FROM %s t', 'mysql' => self::float(), 'sqlite' => TypeCombinator::union(self::float(), self::int()), - 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int()), + 'pdo_pgsql' => TypeCombinator::union(self::float(), self::int()), 'pgsql' => TypeCombinator::union(self::float(), self::int()), 'mssql' => self::mixed(), 'mysqlResult' => 0.0, 'sqliteResult' => 0, - 'pdoPgsqlResult' => '0', + 'pdoPgsqlResult' => 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'COALESCE(t.col_float_nullable, 0.0)' => [ @@ -4254,15 +4271,15 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_float_nullable, 0.0) FROM %s t', 'mysql' => self::float(), 'sqlite' => self::float(), - 'pdo_pgsql' => self::numericString(), + 'pdo_pgsql' => TypeCombinator::union(self::float(), self::numericString()), 'pgsql' => TypeCombinator::union(self::float(), self::numericString()), 'mssql' => self::mixed(), 'mysqlResult' => 0.0, 'sqliteResult' => 0.0, - 'pdoPgsqlResult' => '0', + 'pdoPgsqlResult' => 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'COALESCE(t.col_int_nullable, t.col_decimal_nullable, 0)' => [ @@ -4286,15 +4303,15 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0) FROM %s t', 'mysql' => self::float(), 'sqlite' => TypeCombinator::union(self::float(), self::int()), - 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int()), + 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'mssql' => self::mixed(), 'mysqlResult' => 0.0, 'sqliteResult' => 0, - 'pdoPgsqlResult' => '0', + 'pdoPgsqlResult' => 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0.0)' => [ @@ -4302,15 +4319,15 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0.0) FROM %s t', 'mysql' => self::float(), 'sqlite' => TypeCombinator::union(self::float(), self::int()), - 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int()), + 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'mssql' => self::mixed(), 'mysqlResult' => 0.0, 'sqliteResult' => 0.0, - 'pdoPgsqlResult' => '0', + 'pdoPgsqlResult' => 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0e0)' => [ @@ -4318,15 +4335,15 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0e0) FROM %s t', 'mysql' => self::float(), 'sqlite' => TypeCombinator::union(self::float(), self::int()), - 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int()), + 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'mssql' => self::mixed(), 'mysqlResult' => 0.0, 'sqliteResult' => 0.0, - 'pdoPgsqlResult' => '0', + 'pdoPgsqlResult' => 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield "COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, '0')" => [ @@ -4334,15 +4351,15 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, \'0\') FROM %s t', 'mysql' => self::numericString(), 'sqlite' => TypeCombinator::union(self::float(), self::int(), self::numericString()), - 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int()), + 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'mssql' => self::mixed(), 'mysqlResult' => '0', 'sqliteResult' => '0', - 'pdoPgsqlResult' => '0', + 'pdoPgsqlResult' => 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, t.col_string)' => [ @@ -4371,10 +4388,10 @@ public static function provideCases(): iterable 'mssql' => self::mixed(), 'mysqlResult' => 1.0, 'sqliteResult' => 1, - 'pdoPgsqlResult' => '1', + 'pdoPgsqlResult' => 1.0, 'pgsqlResult' => 1.0, 'mssqlResult' => 1.0, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'COALESCE(t.col_string_nullable, t.col_int)' => [ @@ -4996,6 +5013,15 @@ private function resolveDefaultBooleanStringification(?string $driver, int $php, return $this->resolveDefaultStringification($driver, $php, $configName); } + private function resolveDefaultFloatStringification(?string $driver, int $php, string $configName): bool + { + if ($php < 80400 && $driver === DriverDetector::PDO_PGSQL) { + return true; // pdo_pgsql does stringify floats even without ATTR_STRINGIFY_FETCHES prior to PHP 8.4 + } + + return $this->resolveDefaultStringification($driver, $php, $configName); + } + private function getHumanReadablePhpVersion(int $phpVersion): string { return floor($phpVersion / 10000) . '.' . floor(($phpVersion % 10000) / 100); @@ -5024,6 +5050,10 @@ private function shouldStringify(string $stringification, ?string $driverType, i return $this->resolveDefaultBooleanStringification($driverType, $phpVersion, $configName); } + if ($stringification === self::STRINGIFY_PG_FLOAT) { + return $this->resolveDefaultFloatStringification($driverType, $phpVersion, $configName); + } + throw new LogicException('Unknown stringification: ' . $stringification); } From 516967588266f7476fdff05350ff60130fa76b0c Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Mon, 9 Sep 2024 15:54:38 +0200 Subject: [PATCH 2/3] Fix asserts, add Dockerfile for PHP 8.4 --- .../Doctrine/Query/QueryResultTypeWalker.php | 5 ++ ...eryResultTypeWalkerFetchTypeMatrixTest.php | 74 +++++++++++++++---- tests/Platform/README.md | 10 ++- tests/Platform/docker/Dockerfile84 | 24 ++++++ tests/Platform/docker/docker-compose.yml | 14 ++++ 5 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 tests/Platform/docker/Dockerfile84 diff --git a/src/Type/Doctrine/Query/QueryResultTypeWalker.php b/src/Type/Doctrine/Query/QueryResultTypeWalker.php index 54d836c6..970523de 100644 --- a/src/Type/Doctrine/Query/QueryResultTypeWalker.php +++ b/src/Type/Doctrine/Query/QueryResultTypeWalker.php @@ -1587,6 +1587,11 @@ public function walkLiteral($literal): string if (stripos($value, 'e') !== false) { $type = new DqlConstantStringType((string) (float) $value, $literal->type); } else { + // if ($this->phpVersion->getVersionId() >= 80400) { + // $type = new ConstantFloatType((float) $value); + // } else { + // $type = new DqlConstantStringType($value, $literal->type); + // } $type = new DqlConstantStringType($value, $literal->type); } diff --git a/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php b/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php index 3faae5a6..28f9c2ed 100644 --- a/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php +++ b/tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php @@ -2743,7 +2743,7 @@ public static function provideCases(): iterable 'pdoPgsqlResult' => 0.125, 'pgsqlResult' => 0.125, 'mssqlResult' => 0.125, - 'stringify' => self::STRINGIFY_DEFAULT, + 'stringify' => self::STRINGIFY_PG_FLOAT, ]; yield 'MAX(t.col_decimal)' => [ @@ -4170,6 +4170,38 @@ public static function provideCases(): iterable 'stringify' => self::STRINGIFY_DEFAULT, ]; + yield 'COALESCE(0, 0)' => [ + 'data' => self::dataDefault(), + 'select' => 'SELECT COALESCE(0, 0) FROM %s t', + 'mysql' => self::int(), + 'sqlite' => self::int(), + 'pdo_pgsql' => self::int(), + 'pgsql' => self::int(), + 'mssql' => self::mixed(), + 'mysqlResult' => 0, + 'sqliteResult' => 0, + 'pdoPgsqlResult' => 0, + 'pgsqlResult' => 0, + 'mssqlResult' => 0, + 'stringify' => self::STRINGIFY_DEFAULT, + ]; + + yield 'COALESCE(1.0, 1.0)' => [ + 'data' => self::dataDefault(), + 'select' => 'SELECT COALESCE(1.0, 1.0) FROM %s t', + 'mysql' => self::numericString(), + 'sqlite' => self::float(), + 'pdo_pgsql' => self::numericString(), + 'pgsql' => self::numericString(), + 'mssql' => self::mixed(), + 'mysqlResult' => '1.0', + 'sqliteResult' => 1.0, + 'pdoPgsqlResult' => '1.0', + 'pgsqlResult' => '1.0', + 'mssqlResult' => '1.0', + 'stringify' => self::STRINGIFY_DEFAULT, + ]; + yield 'COALESCE(1e0, 1.0)' => [ 'data' => self::dataDefault(), 'select' => 'SELECT COALESCE(1e0, 1.0) FROM %s t', @@ -4255,15 +4287,17 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_float_nullable, 0) FROM %s t', 'mysql' => self::float(), 'sqlite' => TypeCombinator::union(self::float(), self::int()), - 'pdo_pgsql' => TypeCombinator::union(self::float(), self::int()), + 'pdo_pgsql' => PHP_VERSION_ID < 80400 + ? TypeCombinator::union(self::numericString(), self::int()) + : TypeCombinator::union(self::float(), self::int()), 'pgsql' => TypeCombinator::union(self::float(), self::int()), 'mssql' => self::mixed(), 'mysqlResult' => 0.0, 'sqliteResult' => 0, - 'pdoPgsqlResult' => 0.0, + 'pdoPgsqlResult' => PHP_VERSION_ID < 80400 ? '0' : 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_PG_FLOAT, + 'stringify' => self::STRINGIFY_DEFAULT, ]; yield 'COALESCE(t.col_float_nullable, 0.0)' => [ @@ -4303,15 +4337,17 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0) FROM %s t', 'mysql' => self::float(), 'sqlite' => TypeCombinator::union(self::float(), self::int()), - 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), + 'pdo_pgsql' => PHP_VERSION_ID < 80400 + ? TypeCombinator::union(self::numericString(), self::int()) + : TypeCombinator::union(self::numericString(), self::int(), self::float()), 'pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'mssql' => self::mixed(), 'mysqlResult' => 0.0, 'sqliteResult' => 0, - 'pdoPgsqlResult' => 0.0, + 'pdoPgsqlResult' => PHP_VERSION_ID < 80400 ? '0' : 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_PG_FLOAT, + 'stringify' => self::STRINGIFY_DEFAULT, ]; yield 'COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0.0)' => [ @@ -4319,15 +4355,17 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0.0) FROM %s t', 'mysql' => self::float(), 'sqlite' => TypeCombinator::union(self::float(), self::int()), - 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), + 'pdo_pgsql' => PHP_VERSION_ID < 80400 + ? TypeCombinator::union(self::numericString(), self::int()) + : TypeCombinator::union(self::numericString(), self::int(), self::float()), 'pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'mssql' => self::mixed(), 'mysqlResult' => 0.0, 'sqliteResult' => 0.0, - 'pdoPgsqlResult' => 0.0, + 'pdoPgsqlResult' => PHP_VERSION_ID < 80400 ? '0' : 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_PG_FLOAT, + 'stringify' => self::STRINGIFY_DEFAULT, ]; yield 'COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0e0)' => [ @@ -4335,15 +4373,17 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, 0e0) FROM %s t', 'mysql' => self::float(), 'sqlite' => TypeCombinator::union(self::float(), self::int()), - 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), + 'pdo_pgsql' => PHP_VERSION_ID < 80400 + ? TypeCombinator::union(self::numericString(), self::int()) + : TypeCombinator::union(self::numericString(), self::int(), self::float()), 'pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'mssql' => self::mixed(), 'mysqlResult' => 0.0, 'sqliteResult' => 0.0, - 'pdoPgsqlResult' => 0.0, + 'pdoPgsqlResult' => PHP_VERSION_ID < 80400 ? '0' : 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_PG_FLOAT, + 'stringify' => self::STRINGIFY_DEFAULT, ]; yield "COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, '0')" => [ @@ -4351,15 +4391,17 @@ public static function provideCases(): iterable 'select' => 'SELECT COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, \'0\') FROM %s t', 'mysql' => self::numericString(), 'sqlite' => TypeCombinator::union(self::float(), self::int(), self::numericString()), - 'pdo_pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), + 'pdo_pgsql' => PHP_VERSION_ID < 80400 + ? TypeCombinator::union(self::numericString(), self::int()) + : TypeCombinator::union(self::numericString(), self::int(), self::float()), 'pgsql' => TypeCombinator::union(self::numericString(), self::int(), self::float()), 'mssql' => self::mixed(), 'mysqlResult' => '0', 'sqliteResult' => '0', - 'pdoPgsqlResult' => 0.0, + 'pdoPgsqlResult' => PHP_VERSION_ID < 80400 ? '0' : 0.0, 'pgsqlResult' => 0.0, 'mssqlResult' => 0.0, - 'stringify' => self::STRINGIFY_PG_FLOAT, + 'stringify' => self::STRINGIFY_DEFAULT, ]; yield 'COALESCE(t.col_int_nullable, t.col_decimal_nullable, t.col_float_nullable, t.col_string)' => [ diff --git a/tests/Platform/README.md b/tests/Platform/README.md index d3678117..06d8b843 100644 --- a/tests/Platform/README.md +++ b/tests/Platform/README.md @@ -8,18 +8,22 @@ Set current working directory to project root. - `printf "UID=$(id -u)\nGID=$(id -g)" > .env` - `docker-compose -f tests/Platform/docker/docker-compose.yml up -d` -# Test behaviour with old stringification +# Test behaviour for PHP 8.0 (old stringification) - `docker-compose -f tests/Platform/docker/docker-compose.yml run --rm php80 composer update` - `docker-compose -f tests/Platform/docker/docker-compose.yml run --rm php80 php -d memory_limit=1G vendor/bin/phpunit --group=platform` -# Test behaviour with new stringification +# Test behaviour for PHP 8.1 (adjusted stringification) - `docker-compose -f tests/Platform/docker/docker-compose.yml run --rm php81 composer update` - `docker-compose -f tests/Platform/docker/docker-compose.yml run --rm php81 php -d memory_limit=1G vendor/bin/phpunit --group=platform` + +# Test behaviour for PHP 8.4 (pdo_pgsql float stringification fix) +- `docker-compose -f tests/Platform/docker/docker-compose.yml run --rm php84 composer update` +- `docker-compose -f tests/Platform/docker/docker-compose.yml run --rm php84 php -d memory_limit=1G vendor/bin/phpunit --group=platform` ``` You can also run utilize those containers for PHPStorm PHPUnit configuration. Since the dataset is huge and takes few minutes to run, you can filter only functions you are interested in: ```sh -docker-compose -f tests/Platform/docker/docker-compose.yml run --rm php81 php -d memory_limit=1G vendor/bin/phpunit --group=platform --filter "AVG" +docker-compose -f tests/Platform/docker/docker-compose.yml run --rm php84 php -d memory_limit=1G vendor/bin/phpunit --group=platform --filter "AVG" ``` diff --git a/tests/Platform/docker/Dockerfile84 b/tests/Platform/docker/Dockerfile84 new file mode 100644 index 00000000..81ac9834 --- /dev/null +++ b/tests/Platform/docker/Dockerfile84 @@ -0,0 +1,24 @@ +FROM php:8.4.0beta4-cli + +# MSSQL +RUN apt update \ + && apt install -y gnupg2 \ + && apt install -y unixodbc-dev unixodbc \ + && curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \ + && curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | tee /etc/apt/sources.list.d/mssql-tools.list \ + && apt update \ + && ACCEPT_EULA=Y apt install -y msodbcsql17 \ + && pecl install sqlsrv \ + && pecl install pdo_sqlsrv \ + && docker-php-ext-enable sqlsrv pdo_sqlsrv + +RUN set -ex \ + && apt update \ + && apt install -y bash zip libpq-dev libsqlite3-dev \ + && pecl install xdebug-3.4 mongodb \ + && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \ + && docker-php-ext-install pdo mysqli pgsql pdo_mysql pdo_pgsql pdo_sqlite \ + && docker-php-ext-enable mongodb # TODO xdebug not yet supported here + +COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer + diff --git a/tests/Platform/docker/docker-compose.yml b/tests/Platform/docker/docker-compose.yml index 73596b72..4a3b0f48 100644 --- a/tests/Platform/docker/docker-compose.yml +++ b/tests/Platform/docker/docker-compose.yml @@ -63,3 +63,17 @@ services: user: ${UID:-1000}:${GID:-1000} volumes: - ../../../:/app + + php84: + depends_on: [mysql, pgsql] + build: + context: . + dockerfile: ./Dockerfile84 + environment: + MYSQL_HOST: mysql + PGSQL_HOST: pgsql + MSSQL_HOST: mssql + working_dir: /app + user: ${UID:-1000}:${GID:-1000} + volumes: + - ../../../:/app From 0d8866981a1662629a0559e969ad0c1408faaf45 Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Mon, 9 Sep 2024 15:55:54 +0200 Subject: [PATCH 3/3] Remove commented code --- src/Type/Doctrine/Query/QueryResultTypeWalker.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Type/Doctrine/Query/QueryResultTypeWalker.php b/src/Type/Doctrine/Query/QueryResultTypeWalker.php index 970523de..54d836c6 100644 --- a/src/Type/Doctrine/Query/QueryResultTypeWalker.php +++ b/src/Type/Doctrine/Query/QueryResultTypeWalker.php @@ -1587,11 +1587,6 @@ public function walkLiteral($literal): string if (stripos($value, 'e') !== false) { $type = new DqlConstantStringType((string) (float) $value, $literal->type); } else { - // if ($this->phpVersion->getVersionId() >= 80400) { - // $type = new ConstantFloatType((float) $value); - // } else { - // $type = new DqlConstantStringType($value, $literal->type); - // } $type = new DqlConstantStringType($value, $literal->type); }