diff --git a/Civi/Api4/Query/SqlEquation.php b/Civi/Api4/Query/SqlEquation.php index f29fb343d8ee..479c6977f876 100644 --- a/Civi/Api4/Query/SqlEquation.php +++ b/Civi/Api4/Query/SqlEquation.php @@ -70,7 +70,17 @@ protected function initialize() { public function render(array $fieldList): string { $output = []; foreach ($this->args as $arg) { - $output[] = is_string($arg) ? $arg : $arg->render($fieldList); + // Just an operator + if (is_string($arg)) { + $output[] = $arg; + } + // Surround fields with COALESCE to handle null values + elseif (is_a($arg, SqlField::class)) { + $output[] = 'COALESCE(' . $arg->render($fieldList) . ', 0)'; + } + else { + $output[] = $arg->render($fieldList); + } } return '(' . implode(' ', $output) . ')'; } diff --git a/tests/phpunit/api/v4/Action/SqlExpressionTest.php b/tests/phpunit/api/v4/Action/SqlExpressionTest.php index b5fb0a15f68e..402bb53ab3c8 100644 --- a/tests/phpunit/api/v4/Action/SqlExpressionTest.php +++ b/tests/phpunit/api/v4/Action/SqlExpressionTest.php @@ -108,7 +108,10 @@ public function testSelectEquations() { '(5 > 11) AS five_greater_eleven', '(5 <= 11) AS five_less_eleven', '(1 BETWEEN 0 AND contact_id) AS is_between', + // These fields don't exist '(illegal * stuff) AS illegal_stuff', + // This field will be null + '(hold_date + 5) AS null_plus_five', ]) ->addWhere('contact_id', '=', $contact['id']) ->setLimit(1) @@ -121,6 +124,7 @@ public function testSelectEquations() { $this->assertTrue($result['five_less_eleven']); $this->assertTrue($result['is_between']); $this->assertArrayNotHasKey('illegal_stuff', $result); + $this->assertEquals('5', $result['null_plus_five']); } }