Skip to content

Commit adb2bbb

Browse files
committed
edge cases
1 parent edaea0d commit adb2bbb

4 files changed

Lines changed: 20 additions & 21 deletions

File tree

src/Database/Adapter/MariaDB.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,11 +2038,10 @@ protected function getOperatorSQL(string $column, Operator $operator, array &$bi
20382038
// A negative base to a fractional exponent is not a real number.
20392039
$whens[] = "WHEN {$col} < 0 THEN {$col}";
20402040
}
2041-
// Positive base: compare with logarithms so POWER() never runs on a value that
2042-
// would overflow (base^exp > max <=> exp * LOG(base) > LOG(max)).
2043-
$whens[] = "WHEN {$col} > 0 AND :$bindKey * LOG({$col}) > LOG(:$maxKey) THEN {$col}";
2044-
// Non-positive base (no overflow risk): compare the computed value directly.
2045-
$whens[] = "WHEN {$col} <= 0 AND POWER({$col}, :$bindKey) > :$maxKey THEN {$col}";
2041+
// Compare magnitudes with logarithms so POWER() never runs on a value that would
2042+
// overflow (|base|^exp > max <=> exp * LOG(|base|) > LOG(max)). Works for both
2043+
// signs; ABS() keeps LOG() defined for negative bases with an integer exponent.
2044+
$whens[] = "WHEN {$col} <> 0 AND :$bindKey * LOG(ABS({$col})) > LOG(:$maxKey) THEN {$col}";
20462045

20472046
$whenSql = \implode(' ', $whens);
20482047
return "{$quotedColumn} = CASE {$whenSql} ELSE POWER({$col}, :$bindKey) END";

src/Database/Adapter/Postgres.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,11 +2596,10 @@ protected function getOperatorSQL(string $column, Operator $operator, array &$bi
25962596
if (\floor($exponent) != $exponent) {
25972597
$whens[] = "WHEN {$col} < 0 THEN {$col}";
25982598
}
2599-
// Positive base: compare with logarithms so POWER() never runs on a value that
2600-
// would overflow (base^exp > max <=> exp * LN(base) > LN(max)).
2601-
$whens[] = "WHEN {$col} > 0 AND :$bindKey * LN({$col}) > LN(:$maxKey) THEN {$col}";
2602-
// Non-positive base (no overflow risk): compare the computed value directly.
2603-
$whens[] = "WHEN {$col} <= 0 AND POWER({$col}, :$bindKey) > :$maxKey THEN {$col}";
2599+
// Compare magnitudes with logarithms so POWER() never runs on a value that would
2600+
// overflow (|base|^exp > max <=> exp * LN(|base|) > LN(max)). Works for both
2601+
// signs; ABS() keeps LN() defined for negative bases with an integer exponent.
2602+
$whens[] = "WHEN {$col} <> 0 AND :$bindKey * LN(ABS({$col})) > LN(:$maxKey) THEN {$col}";
26042603

26052604
$whenSql = \implode(' ', $whens);
26062605
return "{$quotedColumn} = CASE {$whenSql} ELSE POWER({$col}, :$bindKey) END";

src/Database/Adapter/SQLite.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,11 +2110,10 @@ protected function getOperatorSQL(string $column, Operator $operator, array &$bi
21102110
// A negative base to a fractional exponent is not a real number.
21112111
$whens[] = "WHEN {$col} < 0 THEN {$col}";
21122112
}
2113-
// Positive base: compare with logarithms so POWER() never runs on a value that
2114-
// would overflow (base^exp > max <=> exp * LN(base) > LN(max)).
2115-
$whens[] = "WHEN {$col} > 0 AND :$bindKey * LN({$col}) > LN(:$maxKey) THEN {$col}";
2116-
// Non-positive base (no overflow risk): compare the computed value directly.
2117-
$whens[] = "WHEN {$col} <= 0 AND POWER({$col}, :$bindKey) > :$maxKey THEN {$col}";
2113+
// Compare magnitudes with logarithms so POWER() never runs on a value that would
2114+
// overflow (|base|^exp > max <=> exp * LN(|base|) > LN(max)). Works for both
2115+
// signs; ABS() keeps LN() defined for negative bases with an integer exponent.
2116+
$whens[] = "WHEN {$col} <> 0 AND :$bindKey * LN(ABS({$col})) > LN(:$maxKey) THEN {$col}";
21182117

21192118
$whenSql = \implode(' ', $whens);
21202119
return "{$quotedColumn} = CASE {$whenSql} ELSE POWER({$col}, :$bindKey) END";

tests/e2e/Adapter/Scopes/OperatorTests.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,12 +1750,14 @@ public function testOperatorBoundedPowerComputesWithinMax(): void
17501750

17511751
// [id, starting value, operator, expected stored value].
17521752
$cases = [
1753-
['fraction', 0.5, Operator::power(2, 1), 0.25], // 0.5^2 = 0.25, within max 1 → applied
1754-
['negeven', -4.0, Operator::power(2, 20), 16.0], // (-4)^2 = 16, within max 20 → applied
1755-
['within', 2.0, Operator::power(3, 100), 8.0], // 2^3 = 8, within max 100 → applied
1756-
['exceeds', 5.0, Operator::power(3, 100), 5.0], // 5^3 = 125 > 100 → left unchanged
1757-
['negfrac', -4.0, Operator::power(0.5, 100), -4.0], // sqrt(-4) undefined → left unchanged
1758-
['zeroneg', 0.0, Operator::power(-1, 100), 0.0], // 0^-1 undefined → left unchanged
1753+
['fraction', 0.5, Operator::power(2, 1), 0.25], // 0.5^2 = 0.25, within max 1 → applied
1754+
['negeven', -4.0, Operator::power(2, 20), 16.0], // (-4)^2 = 16, within max 20 → applied
1755+
['negodd', -2.0, Operator::power(3, 100), -8.0], // (-2)^3 = -8, within max 100 → applied
1756+
['within', 2.0, Operator::power(3, 100), 8.0], // 2^3 = 8, within max 100 → applied
1757+
['exceeds', 5.0, Operator::power(3, 100), 5.0], // 5^3 = 125 > 100 → left unchanged
1758+
['negexceeds', -10.0, Operator::power(100, 100), -10.0], // (-10)^100 far exceeds max → left unchanged (no overflow error)
1759+
['negfrac', -4.0, Operator::power(0.5, 100), -4.0], // sqrt(-4) undefined → left unchanged
1760+
['zeroneg', 0.0, Operator::power(-1, 100), 0.0], // 0^-1 undefined → left unchanged
17591761
];
17601762

17611763
foreach ($cases as [$id, $start, $operator, $expected]) {

0 commit comments

Comments
 (0)