Skip to content

Commit db28249

Browse files
committed
Address greptile review
1 parent adb2bbb commit db28249

4 files changed

Lines changed: 43 additions & 12 deletions

File tree

src/Database/Adapter/MariaDB.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,6 +2029,8 @@ protected function getOperatorSQL(string $column, Operator $operator, array &$bi
20292029
// Leave the value unchanged only for undefined inputs, then apply the power if
20302030
// the result stays within the max. The exponent is constant, so only the
20312031
// undefined guard its value can actually trigger is emitted.
2032+
$oddInteger = \floor($exponent) == $exponent && ((int) $exponent) % 2 !== 0;
2033+
20322034
$whens = [];
20332035
if ($exponent < 0) {
20342036
// 0 to a negative power is undefined (POWER would error / return NULL).
@@ -2038,10 +2040,18 @@ protected function getOperatorSQL(string $column, Operator $operator, array &$bi
20382040
// A negative base to a fractional exponent is not a real number.
20392041
$whens[] = "WHEN {$col} < 0 THEN {$col}";
20402042
}
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}";
2043+
// Cap by magnitude via logarithms so POWER() never runs on a value that would
2044+
// overflow (base^exp > max <=> exp * LOG(base) > LOG(max)).
2045+
if ($oddInteger) {
2046+
// An odd exponent keeps a negative base negative, and a negative result is
2047+
// always within a positive max, so only cap positive bases; negative bases
2048+
// fall through to POWER() and their (negative) result is applied.
2049+
$whens[] = "WHEN {$col} > 0 AND :$bindKey * LOG({$col}) > LOG(:$maxKey) THEN {$col}";
2050+
} else {
2051+
// Otherwise the result is non-negative, so its magnitude equals its value —
2052+
// cap either sign. ABS() keeps LOG() defined for a negative even-power base.
2053+
$whens[] = "WHEN {$col} <> 0 AND :$bindKey * LOG(ABS({$col})) > LOG(:$maxKey) THEN {$col}";
2054+
}
20452055

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

src/Database/Adapter/Postgres.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2589,17 +2589,27 @@ protected function getOperatorSQL(string $column, Operator $operator, array &$bi
25892589
// undefined guard its value can actually trigger is emitted. PostgreSQL throws
25902590
// a hard error for 0 to a negative power and a negative base to a fractional
25912591
// exponent, so those must never reach POWER().
2592+
$oddInteger = \floor($exponent) == $exponent && ((int) $exponent) % 2 !== 0;
2593+
25922594
$whens = [];
25932595
if ($exponent < 0) {
25942596
$whens[] = "WHEN {$col} = 0 THEN {$col}";
25952597
}
25962598
if (\floor($exponent) != $exponent) {
25972599
$whens[] = "WHEN {$col} < 0 THEN {$col}";
25982600
}
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}";
2601+
// Cap by magnitude via logarithms so POWER() never runs on a value that would
2602+
// overflow (base^exp > max <=> exp * LN(base) > LN(max)).
2603+
if ($oddInteger) {
2604+
// An odd exponent keeps a negative base negative, and a negative result is
2605+
// always within a positive max, so only cap positive bases; negative bases
2606+
// fall through to POWER() and their (negative) result is applied.
2607+
$whens[] = "WHEN {$col} > 0 AND :$bindKey * LN({$col}) > LN(:$maxKey) THEN {$col}";
2608+
} else {
2609+
// Otherwise the result is non-negative, so its magnitude equals its value —
2610+
// cap either sign. ABS() keeps LN() defined for a negative even-power base.
2611+
$whens[] = "WHEN {$col} <> 0 AND :$bindKey * LN(ABS({$col})) > LN(:$maxKey) THEN {$col}";
2612+
}
26032613

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

src/Database/Adapter/SQLite.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,6 +2101,8 @@ protected function getOperatorSQL(string $column, Operator $operator, array &$bi
21012101
// Leave the value unchanged only for undefined inputs, then apply the power if
21022102
// the result stays within the max. The exponent is constant, so only the
21032103
// undefined guard its value can actually trigger is emitted.
2104+
$oddInteger = \floor($exponent) == $exponent && ((int) $exponent) % 2 !== 0;
2105+
21042106
$whens = [];
21052107
if ($exponent < 0) {
21062108
// 0 to a negative power is undefined.
@@ -2110,10 +2112,18 @@ protected function getOperatorSQL(string $column, Operator $operator, array &$bi
21102112
// A negative base to a fractional exponent is not a real number.
21112113
$whens[] = "WHEN {$col} < 0 THEN {$col}";
21122114
}
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}";
2115+
// Cap by magnitude via logarithms so POWER() never runs on a value that would
2116+
// overflow (base^exp > max <=> exp * LN(base) > LN(max)).
2117+
if ($oddInteger) {
2118+
// An odd exponent keeps a negative base negative, and a negative result is
2119+
// always within a positive max, so only cap positive bases; negative bases
2120+
// fall through to POWER() and their (negative) result is applied.
2121+
$whens[] = "WHEN {$col} > 0 AND :$bindKey * LN({$col}) > LN(:$maxKey) THEN {$col}";
2122+
} else {
2123+
// Otherwise the result is non-negative, so its magnitude equals its value —
2124+
// cap either sign. ABS() keeps LN() defined for a negative even-power base.
2125+
$whens[] = "WHEN {$col} <> 0 AND :$bindKey * LN(ABS({$col})) > LN(:$maxKey) THEN {$col}";
2126+
}
21172127

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

tests/e2e/Adapter/Scopes/OperatorTests.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,7 @@ public function testOperatorBoundedPowerComputesWithinMax(): void
17531753
['fraction', 0.5, Operator::power(2, 1), 0.25], // 0.5^2 = 0.25, within max 1 → applied
17541754
['negeven', -4.0, Operator::power(2, 20), 16.0], // (-4)^2 = 16, within max 20 → applied
17551755
['negodd', -2.0, Operator::power(3, 100), -8.0], // (-2)^3 = -8, within max 100 → applied
1756+
['negoddbig', -5.0, Operator::power(3, 100), -125.0], // (-5)^3 = -125, negative so within max 100 → applied
17561757
['within', 2.0, Operator::power(3, 100), 8.0], // 2^3 = 8, within max 100 → applied
17571758
['exceeds', 5.0, Operator::power(3, 100), 5.0], // 5^3 = 125 > 100 → left unchanged
17581759
['negexceeds', -10.0, Operator::power(100, 100), -10.0], // (-10)^100 far exceeds max → left unchanged (no overflow error)

0 commit comments

Comments
 (0)