diff --git a/CRM/Contact/BAO/GroupContactCache.php b/CRM/Contact/BAO/GroupContactCache.php index 417963ee7fd0..bd5e4a30fa30 100644 --- a/CRM/Contact/BAO/GroupContactCache.php +++ b/CRM/Contact/BAO/GroupContactCache.php @@ -721,12 +721,12 @@ protected static function getApiSQL(array $savedSearch, string $addSelect, strin list($idField) = explode(' AS ', $apiParams['select'][0]); $apiParams['select'] = [ $addSelect, - $idField . ' AS smart_group_contact_id', + $idField, ]; $api = \Civi\API\Request::create($savedSearch['api_entity'], 'get', $apiParams); $query = new \Civi\Api4\Query\Api4SelectQuery($api); $query->forceSelectId = FALSE; - $query->getQuery()->having('smart_group_contact_id ' . $excludeClause); + $query->getQuery()->having("$idField $excludeClause"); return $query->getSql(); } diff --git a/Civi/Api4/Query/Api4SelectQuery.php b/Civi/Api4/Query/Api4SelectQuery.php index 21298de2a0e4..5bc18313b5c6 100644 --- a/Civi/Api4/Query/Api4SelectQuery.php +++ b/Civi/Api4/Query/Api4SelectQuery.php @@ -197,6 +197,9 @@ protected function buildSelectClause() { } if ($valid) { $alias = $expr->getAlias(); + if ($alias != $expr->getExpr() && isset($this->apiFieldSpec[$alias])) { + throw new \API_Exception('Cannot use existing field name as alias'); + } $this->selectAliases[$alias] = $expr->getExpr(); $this->query->select($expr->render($this->apiFieldSpec) . " AS `$alias`"); } diff --git a/Civi/Api4/Query/SqlField.php b/Civi/Api4/Query/SqlField.php index 712bd7b8cc69..67f1c206a6ff 100644 --- a/Civi/Api4/Query/SqlField.php +++ b/Civi/Api4/Query/SqlField.php @@ -17,6 +17,9 @@ class SqlField extends SqlExpression { protected function initialize() { + if ($this->alias && $this->alias !== $this->expr) { + throw new \API_Exception("Aliasing field names is not allowed, only expressions can have an alias."); + } $this->fields[] = $this->expr; } diff --git a/tests/phpunit/api/v4/Action/SqlExpressionTest.php b/tests/phpunit/api/v4/Action/SqlExpressionTest.php index 3145c9d65657..f99242e03e47 100644 --- a/tests/phpunit/api/v4/Action/SqlExpressionTest.php +++ b/tests/phpunit/api/v4/Action/SqlExpressionTest.php @@ -31,7 +31,7 @@ class SqlExpressionTest extends UnitTestCase { public function testSelectNull() { Contact::create()->addValue('first_name', 'bob')->setCheckPermissions(FALSE)->execute(); $result = Contact::get() - ->addSelect('NULL AS nothing', 'NULL', 'NULL AS b*d char', 'first_name AS firsty') + ->addSelect('NULL AS nothing', 'NULL', 'NULL AS b*d char', 'first_name') ->addWhere('first_name', '=', 'bob') ->setLimit(1) ->execute() @@ -39,7 +39,7 @@ public function testSelectNull() { $this->assertNull($result['nothing']); $this->assertNull($result['NULL']); $this->assertNull($result['b_d_char']); - $this->assertEquals('bob', $result['firsty']); + $this->assertEquals('bob', $result['first_name']); $this->assertArrayNotHasKey('b*d char', $result); } @@ -60,16 +60,40 @@ public function testSelectNumbers() { public function testSelectStrings() { Contact::create()->addValue('first_name', 'bob')->setCheckPermissions(FALSE)->execute(); $result = Contact::get() - ->addSelect('first_name AS bob') + ->addSelect('first_name') ->addSelect('"hello world" AS hi') ->addSelect('"can\'t \"quote\"" AS quot') ->addWhere('first_name', '=', 'bob') ->setLimit(1) ->execute() ->first(); - $this->assertEquals('bob', $result['bob']); + $this->assertEquals('bob', $result['first_name']); $this->assertEquals('hello world', $result['hi']); $this->assertEquals('can\'t "quote"', $result['quot']); } + public function testSelectAlias() { + try { + Contact::get() + ->addSelect('first_name AS bob') + ->execute(); + } + catch (\API_Exception $e) { + $msg = $e->getMessage(); + } + $this->assertContains('alias', $msg); + try { + Contact::get() + ->addSelect('55 AS sort_name') + ->execute(); + } + catch (\API_Exception $e) { + $msg = $e->getMessage(); + } + $this->assertContains('existing field name', $msg); + Contact::get() + ->addSelect('55 AS ok_alias') + ->execute(); + } + }