From 4dccefa689482af930c3f00fe86c9df6291a8b5d Mon Sep 17 00:00:00 2001 From: Taras Omelianchuk Date: Thu, 25 Sep 2025 14:46:27 +0300 Subject: [PATCH] fix: Resolve evaluation issues in SUM() and CONVERT_TZ() functions --- .../Expression/FunctionEvaluator.php | 16 +++++++- tests/EndToEndTest.php | 40 +++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/Processor/Expression/FunctionEvaluator.php b/src/Processor/Expression/FunctionEvaluator.php index 60c81b6d..c6db5e8f 100644 --- a/src/Processor/Expression/FunctionEvaluator.php +++ b/src/Processor/Expression/FunctionEvaluator.php @@ -353,9 +353,13 @@ private static function sqlCount( } /** - * @param array $columns + * @param FakePdoInterface $conn + * @param Scope $scope + * @param FunctionExpression $expr + * @param QueryResult $result * - * @return ?numeric + * @return float|int|mixed|string|null + * @throws ProcessorException */ private static function sqlSum( FakePdoInterface $conn, @@ -368,6 +372,10 @@ private static function sqlSum( $sum = 0; if (!$result->rows) { + if ($expr instanceof FunctionExpression) { + return self::evaluate($conn, $scope, $expr, [], $result); + } + return null; } @@ -1575,6 +1583,10 @@ private static function sqlConvertTz( throw new \InvalidArgumentException("CONVERT_TZ() requires exactly 3 arguments"); } + if ($args[0] instanceof ColumnExpression && empty($row)) { + return null; + } + /** @var string|null $dtValue */ $dtValue = Evaluator::evaluate($conn, $scope, $args[0], $row, $result); /** @var string|null $fromTzValue */ diff --git a/tests/EndToEndTest.php b/tests/EndToEndTest.php index bd6118d1..f59be4f0 100644 --- a/tests/EndToEndTest.php +++ b/tests/EndToEndTest.php @@ -1516,4 +1516,44 @@ public function leastWithExceptionProvider(): iterable yield ['Should fail with single argument' => [1]]; yield ['Should fail without any arguments' => []]; } + + public function testNestedFunctions() + { + $pdo = self::getConnectionToFullDB(); + + $query = $pdo->prepare(" + SELECT + SUM( + TIMESTAMPDIFF( + SECOND, + CONVERT_TZ('2025-12-31 22:59:59', 'Europe/Kyiv', 'Europe/Kyiv'), + CONVERT_TZ('2025-12-31 23:59:59', 'Europe/Kyiv', 'Europe/Kyiv') + ) + ) + "); + $query->execute(); + + $this->assertSame(3600, (int)$query->fetchColumn()); + } + + public function testNestedFunctionsFromDB() + { + $pdo = self::getConnectionToFullDB(); + $count = $pdo->query("SELECT COUNT(*) FROM video_game_characters")->fetchColumn(); + + $query = $pdo->prepare(" + SELECT SUM( + TIMESTAMPDIFF( + SECOND, + CONVERT_TZ(`created_on`, 'Europe/Kyiv', 'Europe/Kyiv'), + CONVERT_TZ(`created_on` + INTERVAL 1 SECOND, 'Europe/Kyiv', 'Europe/Kyiv') + ) + ) + FROM `video_game_characters` + "); + + $query->execute(); + + $this->assertSame((int)$count, (int)$query->fetchColumn()); + } }