Skip to content

Commit ad91388

Browse files
janedbalondrejmirtes
authored andcommitted
QueryResultTypeWalker: fix nullability checks over unknown type
1 parent 3d10eab commit ad91388

File tree

4 files changed

+52
-12
lines changed

4 files changed

+52
-12
lines changed

Diff for: src/Type/Doctrine/Query/QueryResultTypeWalker.php

+12-12
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ public function walkFunction($function): string
376376
new FloatType()
377377
);
378378

379-
if (TypeCombinator::containsNull($exprType)) {
379+
if ($this->canBeNull($exprType)) {
380380
$type = TypeCombinator::addNull($type);
381381
}
382382

@@ -388,7 +388,7 @@ public function walkFunction($function): string
388388
$secondExprType = $this->unmarshalType($function->secondArithmetic->dispatch($this));
389389

390390
$type = IntegerRangeType::fromInterval(0, null);
391-
if (TypeCombinator::containsNull($firstExprType) || TypeCombinator::containsNull($secondExprType)) {
391+
if ($this->canBeNull($firstExprType) || $this->canBeNull($secondExprType)) {
392392
$type = TypeCombinator::addNull($type);
393393
}
394394

@@ -399,7 +399,7 @@ public function walkFunction($function): string
399399

400400
foreach ($function->concatExpressions as $expr) {
401401
$type = $this->unmarshalType($expr->dispatch($this));
402-
$hasNull = $hasNull || TypeCombinator::containsNull($type);
402+
$hasNull = $hasNull || $this->canBeNull($type);
403403
}
404404

405405
$type = new StringType();
@@ -420,7 +420,7 @@ public function walkFunction($function): string
420420
$intervalExprType = $this->unmarshalType($function->intervalExpression->dispatch($this));
421421

422422
$type = new StringType();
423-
if (TypeCombinator::containsNull($dateExprType) || TypeCombinator::containsNull($intervalExprType)) {
423+
if ($this->canBeNull($dateExprType) || $this->canBeNull($intervalExprType)) {
424424
$type = TypeCombinator::addNull($type);
425425
}
426426

@@ -434,7 +434,7 @@ public function walkFunction($function): string
434434
new IntegerType(),
435435
new FloatType()
436436
);
437-
if (TypeCombinator::containsNull($date1ExprType) || TypeCombinator::containsNull($date2ExprType)) {
437+
if ($this->canBeNull($date1ExprType) || $this->canBeNull($date2ExprType)) {
438438
$type = TypeCombinator::addNull($type);
439439
}
440440

@@ -444,7 +444,7 @@ public function walkFunction($function): string
444444
$stringPrimaryType = $this->unmarshalType($function->stringPrimary->dispatch($this));
445445

446446
$type = IntegerRangeType::fromInterval(0, null);
447-
if (TypeCombinator::containsNull($stringPrimaryType)) {
447+
if ($this->canBeNull($stringPrimaryType)) {
448448
$type = TypeCombinator::addNull($type);
449449
}
450450

@@ -455,7 +455,7 @@ public function walkFunction($function): string
455455
$secondExprType = $this->unmarshalType($this->walkStringPrimary($function->secondStringPrimary));
456456

457457
$type = IntegerRangeType::fromInterval(0, null);
458-
if (TypeCombinator::containsNull($firstExprType) || TypeCombinator::containsNull($secondExprType)) {
458+
if ($this->canBeNull($firstExprType) || $this->canBeNull($secondExprType)) {
459459
$type = TypeCombinator::addNull($type);
460460
}
461461

@@ -467,7 +467,7 @@ public function walkFunction($function): string
467467
$stringPrimaryType = $this->unmarshalType($function->stringPrimary->dispatch($this));
468468

469469
$type = new StringType();
470-
if (TypeCombinator::containsNull($stringPrimaryType)) {
470+
if ($this->canBeNull($stringPrimaryType)) {
471471
$type = TypeCombinator::addNull($type);
472472
}
473473

@@ -478,7 +478,7 @@ public function walkFunction($function): string
478478
$secondExprType = $this->unmarshalType($this->walkSimpleArithmeticExpression($function->secondSimpleArithmeticExpression));
479479

480480
$type = IntegerRangeType::fromInterval(0, null);
481-
if (TypeCombinator::containsNull($firstExprType) || TypeCombinator::containsNull($secondExprType)) {
481+
if ($this->canBeNull($firstExprType) || $this->canBeNull($secondExprType)) {
482482
$type = TypeCombinator::addNull($type);
483483
}
484484

@@ -493,7 +493,7 @@ public function walkFunction($function): string
493493
$exprType = $this->unmarshalType($this->walkSimpleArithmeticExpression($function->simpleArithmeticExpression));
494494

495495
$type = new FloatType();
496-
if (TypeCombinator::containsNull($exprType)) {
496+
if ($this->canBeNull($exprType)) {
497497
$type = TypeCombinator::addNull($type);
498498
}
499499

@@ -510,7 +510,7 @@ public function walkFunction($function): string
510510
}
511511

512512
$type = new StringType();
513-
if (TypeCombinator::containsNull($stringType) || TypeCombinator::containsNull($firstExprType) || TypeCombinator::containsNull($secondExprType)) {
513+
if ($this->canBeNull($stringType) || $this->canBeNull($firstExprType) || $this->canBeNull($secondExprType)) {
514514
$type = TypeCombinator::addNull($type);
515515
}
516516

@@ -714,7 +714,7 @@ public function walkCoalesceExpression($coalesceExpression): string
714714
}
715715

716716
$type = $this->unmarshalType($expression->dispatch($this));
717-
$allTypesContainNull = $allTypesContainNull && TypeCombinator::containsNull($type);
717+
$allTypesContainNull = $allTypesContainNull && $this->canBeNull($type);
718718

719719
// Some drivers manipulate the types, lets avoid false positives by generalizing constant types
720720
// e.g. sqlsrv: "COALESCE returns the data type of value with the highest precedence"

Diff for: tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php

+16
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use DateTime;
88
use DateTimeImmutable;
99
use Doctrine\Common\Collections\ArrayCollection;
10+
use Doctrine\DBAL\Types\Type as DbalType;
1011
use Doctrine\ORM\EntityManagerInterface;
1112
use Doctrine\ORM\Mapping\Column;
1213
use Doctrine\ORM\Tools\SchemaTool;
@@ -44,6 +45,7 @@
4445
use QueryResult\EntitiesEnum\IntEnum;
4546
use QueryResult\EntitiesEnum\StringEnum;
4647
use Throwable;
48+
use Type\Doctrine\data\QueryResult\CustomIntType;
4749
use function array_merge;
4850
use function array_shift;
4951
use function assert;
@@ -76,6 +78,10 @@ public static function setUpBeforeClass(): void
7678
$em = require __DIR__ . '/../data/QueryResult/entity-manager.php';
7779
self::$em = $em;
7880

81+
if (!DbalType::hasType(CustomIntType::NAME)) {
82+
DbalType::addType(CustomIntType::NAME, CustomIntType::class);
83+
}
84+
7985
$schemaTool = new SchemaTool($em);
8086
$classes = $em->getMetadataFactory()->getAllMetadata();
8187
$schemaTool->createSchema($classes);
@@ -1241,6 +1247,16 @@ public function getTestData(): iterable
12411247
',
12421248
];
12431249

1250+
yield 'abs function with mixed' => [
1251+
$this->constantArray([
1252+
[new ConstantIntegerType(1), TypeCombinator::addNull($this->unumericStringified())],
1253+
]),
1254+
'
1255+
SELECT ABS(o.mixedColumn)
1256+
FROM QueryResult\Entities\One o
1257+
',
1258+
];
1259+
12441260
yield 'bit_and function' => [
12451261
$this->constantArray([
12461262
[new ConstantIntegerType(1), $this->uintStringified()],
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Type\Doctrine\data\QueryResult;
4+
5+
use Doctrine\DBAL\Types\IntegerType;
6+
7+
class CustomIntType extends IntegerType
8+
{
9+
10+
public const NAME = 'custom_int';
11+
12+
public function getName(): string
13+
{
14+
return self::NAME;
15+
}
16+
17+
}

Diff for: tests/Type/Doctrine/data/QueryResult/Entities/One.php

+7
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ class One
7474
*/
7575
public $embedded;
7676

77+
/**
78+
* @Column(type="custom_int", nullable=true)
79+
*
80+
* @var mixed
81+
*/
82+
public $mixedColumn;
83+
7784
public function __construct()
7885
{
7986
$this->subOne = new SubOne();

0 commit comments

Comments
 (0)