@@ -414,17 +414,17 @@ public function walkFunction($function): string
414
414
return $ this ->marshalType (IntegerRangeType::fromInterval (0 , null ));
415
415
416
416
case $ function instanceof AST \Functions \AbsFunction:
417
- // mysql sqlite pdo_pgsql pgsql
418
- // col_float => float float string float
419
- // col_decimal => string float string string
420
- // col_int => int int int int
421
- // col_bigint => int int int int
417
+ // mysql sqlite pdo_pgsql pgsql
418
+ // col_float => float float string float
419
+ // col_decimal => string float|int string string
420
+ // col_int => int int int int
421
+ // col_bigint => int int int int
422
422
//
423
- // ABS(col_float) => float float string float
424
- // ABS(col_decimal) => string float string string
425
- // ABS(col_int) => int int int int
426
- // ABS(col_bigint) => int int int int
427
- // ABS(col_string) => float float x x
423
+ // ABS(col_float) => float float string float
424
+ // ABS(col_decimal) => string float|int string string
425
+ // ABS(col_int) => int int int int
426
+ // ABS(col_bigint) => int int int int
427
+ // ABS(col_string) => float float x x
428
428
429
429
$ exprType = $ this ->unmarshalType ($ this ->walkSimpleArithmeticExpression ($ function ->simpleArithmeticExpression ));
430
430
$ exprType = $ this ->castStringLiteralForFloatExpression ($ exprType );
@@ -434,20 +434,14 @@ public function walkFunction($function): string
434
434
$ nullable = $ this ->canBeNull ($ exprType );
435
435
436
436
if ($ exprTypeNoNull ->isInteger ()->yes ()) {
437
- $ positiveInt = $ this ->canBeNull ($ exprType )
438
- ? TypeCombinator::addNull (IntegerRangeType::fromInterval (0 , null ))
439
- : IntegerRangeType::fromInterval (0 , null );
440
- return $ this ->marshalType ($ positiveInt );
437
+ $ nonNegativeInt = $ this ->createNonNegativeInteger ($ nullable );
438
+ return $ this ->marshalType ($ nonNegativeInt );
441
439
}
442
440
443
- if ($ exprTypeNoNull -> isFloat ()-> yes () || $ exprTypeNoNull -> isNumericString ()-> yes ( )) {
441
+ if ($ this -> containsOnlyTypes ( $ exprTypeNoNull , [ new IntegerType (), new FloatType (), $ this -> createNumericString ( false )] )) {
444
442
return $ this ->marshalType ($ exprType ); // retains underlying type
445
443
}
446
444
447
- if ($ exprTypeNoNull ->isString ()->yes ()) {
448
- return $ this ->marshalType ($ this ->createFloat ($ nullable ));
449
- }
450
-
451
445
return $ this ->marshalType (new MixedType ());
452
446
453
447
case $ function instanceof AST \Functions \BitAndFunction:
@@ -598,7 +592,7 @@ public function walkFunction($function): string
598
592
$ exprType = $ this ->unmarshalType ($ this ->walkSimpleArithmeticExpression ($ function ->simpleArithmeticExpression ));
599
593
$ exprTypeNoNull = TypeCombinator::removeNull ($ exprType );
600
594
601
- if (!$ exprTypeNoNull -> isFloat ()-> yes () && ! $ exprTypeNoNull-> isNumericString ()-> yes () && ! $ exprTypeNoNull -> isInteger ()-> yes ( )) {
595
+ if (!$ this -> containsOnlyNumericTypes ( $ exprTypeNoNull )) {
602
596
return $ this ->marshalType (new MixedType ()); // dont try to deal with non-numeric args
603
597
}
604
598
@@ -824,12 +818,27 @@ private function createFloat(bool $nullable): Type
824
818
return $ nullable ? TypeCombinator::addNull ($ float ) : $ float ;
825
819
}
826
820
821
+ private function createFloatOrInt (bool $ nullable ): Type
822
+ {
823
+ $ union = TypeCombinator::union (
824
+ new FloatType (),
825
+ new IntegerType ()
826
+ );
827
+ return $ nullable ? TypeCombinator::addNull ($ union ) : $ union ;
828
+ }
829
+
827
830
private function createInteger (bool $ nullable ): Type
828
831
{
829
832
$ integer = new IntegerType ();
830
833
return $ nullable ? TypeCombinator::addNull ($ integer ) : $ integer ;
831
834
}
832
835
836
+ private function createNonNegativeInteger (bool $ nullable ): Type
837
+ {
838
+ $ integer = IntegerRangeType::fromInterval (0 , null );
839
+ return $ nullable ? TypeCombinator::addNull ($ integer ) : $ integer ;
840
+ }
841
+
833
842
private function createNumericString (bool $ nullable ): Type
834
843
{
835
844
$ numericString = TypeCombinator::intersect (
@@ -840,6 +849,18 @@ private function createNumericString(bool $nullable): Type
840
849
return $ nullable ? TypeCombinator::addNull ($ numericString ) : $ numericString ;
841
850
}
842
851
852
+ private function containsOnlyNumericTypes (
853
+ Type ...$ checkedTypes
854
+ ): bool
855
+ {
856
+ foreach ($ checkedTypes as $ checkedType ) {
857
+ if (!$ this ->containsOnlyTypes ($ checkedType , [new IntegerType (), new FloatType (), $ this ->createNumericString (false )])) {
858
+ return false ;
859
+ }
860
+ }
861
+ return true ;
862
+ }
863
+
843
864
/**
844
865
* @param list<Type> $allowedTypes
845
866
*/
@@ -1636,33 +1657,36 @@ public function walkArithmeticTerm($term): string
1636
1657
*/
1637
1658
private function inferPlusMinusTimesType (array $ termTypes ): Type
1638
1659
{
1639
- // mysql sqlite pdo_pgsql pgsql
1640
- // col_float float float string float
1641
- // col_decimal string float string string
1642
- // col_int int int int int
1643
- // col_bigint int int int int
1644
- // col_bool int int bool bool
1660
+ // mysql sqlite pdo_pgsql pgsql
1661
+ // col_float float float string float
1662
+ // col_decimal string float|int string string
1663
+ // col_int int int int int
1664
+ // col_bigint int int int int
1665
+ // col_bool int int bool bool
1645
1666
//
1646
- // col_int + col_int int int int int
1647
- // col_int + col_float float float string float
1648
- // col_float + col_float float float string float
1649
- // col_float + col_decimal float float string float
1650
- // col_int + col_decimal string float string string
1651
- // col_decimal + col_decimal string float string string
1652
- // col_string + col_string float int x x
1653
- // col_int + col_string float int x x
1654
- // col_bool + col_bool int int x x
1655
- // col_int + col_bool int int x x
1656
- // col_float + col_string float float x x
1657
- // col_decimal + col_string float float x x
1658
- // col_float + col_bool float float x x
1659
- // col_decimal + col_bool string float x x
1667
+ // col_int + col_int int int int int
1668
+ // col_int + col_float float float string float
1669
+ // col_float + col_float float float string float
1670
+ // col_float + col_decimal float float string float
1671
+ // col_int + col_decimal string float|int string string
1672
+ // col_decimal + col_decimal string float|int string string
1673
+ // col_string + col_string float int x x
1674
+ // col_int + col_string float int x x
1675
+ // col_bool + col_bool int int x x
1676
+ // col_int + col_bool int int x x
1677
+ // col_float + col_string float float x x
1678
+ // col_decimal + col_string float float|int x x
1679
+ // col_float + col_bool float float x x
1680
+ // col_decimal + col_bool string float|int x x
1660
1681
1661
1682
$ driverType = DriverType::detect ($ this ->em ->getConnection ());
1662
1683
$ types = [];
1684
+ $ typesNoNull = [];
1663
1685
1664
1686
foreach ($ termTypes as $ termType ) {
1665
- $ types [] = $ this ->generalizeLiteralType ($ termType , false );
1687
+ $ generalizedType = $ this ->generalizeLiteralType ($ termType , false );
1688
+ $ types [] = $ generalizedType ;
1689
+ $ typesNoNull [] = TypeCombinator::removeNull ($ generalizedType );
1666
1690
}
1667
1691
1668
1692
$ union = TypeCombinator::union (...$ types );
@@ -1674,21 +1698,23 @@ private function inferPlusMinusTimesType(array $termTypes): Type
1674
1698
}
1675
1699
1676
1700
if ($ driverType === DriverType::PDO_PGSQL ) {
1677
- if ($ this ->containsOnlyTypes ($ unionWithoutNull, [ new IntegerType (), new FloatType (), $ this -> createNumericString ( false )] )) {
1701
+ if ($ this ->containsOnlyNumericTypes ($ unionWithoutNull )) {
1678
1702
return $ this ->createNumericString ($ nullable );
1679
1703
}
1680
1704
}
1681
1705
1682
1706
if ($ driverType === DriverType::SQLITE3 || $ driverType === DriverType::PDO_SQLITE ) {
1683
- if ($ this ->containsOnlyTypes ( $ unionWithoutNull , [ new IntegerType (), new FloatType ()] )) {
1684
- return $ this -> createFloat ( $ nullable );
1707
+ if (! $ this ->containsOnlyNumericTypes (... $ typesNoNull )) {
1708
+ return new MixedType ( );
1685
1709
}
1686
- if ( $ this -> containsOnlyTypes ( $ unionWithoutNull , [ new IntegerType (), new StringType ()])) {
1687
- return $ this -> createInteger ( $ nullable );
1688
- }
1689
- if ( $ this ->containsOnlyTypes ( $ unionWithoutNull , [ new FloatType (), new StringType ()])) {
1690
- return $ this -> createFloat ( $ nullable );
1710
+
1711
+ foreach ( $ typesNoNull as $ typeNoNull ) {
1712
+ if ( $ typeNoNull -> isFloat ()-> yes ()) {
1713
+ return $ this ->createFloat ( $ nullable );
1714
+ }
1691
1715
}
1716
+
1717
+ return $ this ->createFloatOrInt ($ nullable );
1692
1718
}
1693
1719
1694
1720
if ($ driverType === DriverType::MYSQLI || $ driverType === DriverType::PDO_MYSQL || $ driverType === DriverType::PGSQL ) {
@@ -1700,20 +1726,11 @@ private function inferPlusMinusTimesType(array $termTypes): Type
1700
1726
return $ this ->createNumericString ($ nullable );
1701
1727
}
1702
1728
1703
- if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new IntegerType (), new StringType ()])) {
1704
- return $ this ->createFloat ($ nullable );
1705
- }
1706
-
1707
- if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new FloatType (), new StringType ()])) {
1708
- return $ this ->createFloat ($ nullable );
1709
- }
1710
-
1711
- if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new IntegerType (), new FloatType (), $ this ->createNumericString (false )])) {
1729
+ if ($ this ->containsOnlyNumericTypes ($ unionWithoutNull )) {
1712
1730
return $ this ->createFloat ($ nullable );
1713
1731
}
1714
1732
}
1715
1733
1716
- // postgre fails and other drivers are unknown
1717
1734
return new MixedType ();
1718
1735
}
1719
1736
@@ -1724,16 +1741,16 @@ private function inferDivisionType(array $termTypes): Type
1724
1741
{
1725
1742
// mysql sqlite pdo_pgsql pgsql
1726
1743
// col_float => float float string float
1727
- // col_decimal => string float string string
1744
+ // col_decimal => string float|int string string
1728
1745
// col_int => int int int int
1729
1746
// col_bigint => int int int int
1730
1747
//
1731
1748
// col_int / col_int string int int int
1732
1749
// col_int / col_float float float string float
1733
1750
// col_float / col_float float float string float
1734
1751
// col_float / col_decimal float float string float
1735
- // col_int / col_decimal string float string string
1736
- // col_decimal / col_decimal string float string string
1752
+ // col_int / col_decimal string float|int string string
1753
+ // col_decimal / col_decimal string float|int string string
1737
1754
// col_string / col_string null null x x
1738
1755
// col_int / col_string null null x x
1739
1756
// col_bool / col_bool string int x x
@@ -1745,9 +1762,12 @@ private function inferDivisionType(array $termTypes): Type
1745
1762
1746
1763
$ driverType = DriverType::detect ($ this ->em ->getConnection ());
1747
1764
$ types = [];
1765
+ $ typesNoNull = [];
1748
1766
1749
1767
foreach ($ termTypes as $ termType ) {
1750
- $ types [] = $ this ->generalizeLiteralType ($ termType , false );
1768
+ $ generalizedType = $ this ->generalizeLiteralType ($ termType , false );
1769
+ $ types [] = $ generalizedType ;
1770
+ $ typesNoNull [] = TypeCombinator::removeNull ($ generalizedType );
1751
1771
}
1752
1772
1753
1773
$ union = TypeCombinator::union (...$ types );
@@ -1771,15 +1791,17 @@ private function inferDivisionType(array $termTypes): Type
1771
1791
}
1772
1792
1773
1793
if ($ driverType === DriverType::SQLITE3 || $ driverType === DriverType::PDO_SQLITE ) {
1774
- if ($ this ->containsOnlyTypes ( $ unionWithoutNull , [ new IntegerType (), new FloatType ()] )) {
1775
- return $ this -> createFloat ( $ nullable );
1794
+ if (! $ this ->containsOnlyNumericTypes (... $ typesNoNull )) {
1795
+ return new MixedType ( );
1776
1796
}
1777
- if ( $ this -> containsOnlyTypes ( $ unionWithoutNull , [ new IntegerType (), new StringType ()])) {
1778
- return $ this -> createInteger ( true );
1779
- }
1780
- if ( $ this ->containsOnlyTypes ( $ unionWithoutNull , [ new FloatType (), new StringType ()])) {
1781
- return $ this -> createFloat ( true );
1797
+
1798
+ foreach ( $ typesNoNull as $ typeNoNull ) {
1799
+ if ( $ typeNoNull -> isFloat ()-> yes ()) {
1800
+ return $ this ->createFloat ( $ nullable );
1801
+ }
1782
1802
}
1803
+
1804
+ return $ this ->createFloatOrInt ($ nullable );
1783
1805
}
1784
1806
1785
1807
if ($ driverType === DriverType::MYSQLI || $ driverType === DriverType::PDO_MYSQL || $ driverType === DriverType::PGSQL ) {
@@ -1795,17 +1817,9 @@ private function inferDivisionType(array $termTypes): Type
1795
1817
return $ this ->createFloat ($ nullable );
1796
1818
}
1797
1819
1798
- if ($ this ->containsOnlyTypes ($ unionWithoutNull, [ new IntegerType (), new FloatType (), $ this -> createNumericString ( false )] )) {
1820
+ if ($ this ->containsOnlyNumericTypes ($ unionWithoutNull )) {
1799
1821
return $ this ->createFloat ($ nullable );
1800
1822
}
1801
-
1802
- if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new IntegerType (), new StringType ()])) {
1803
- return $ this ->createFloat (true );
1804
- }
1805
-
1806
- if ($ this ->containsOnlyTypes ($ unionWithoutNull , [new FloatType (), new StringType ()])) {
1807
- return $ this ->createFloat (true );
1808
- }
1809
1823
}
1810
1824
1811
1825
return new MixedType ();
0 commit comments