From f8bf8e26df5ffb21ef99346cf7efda3d848cff0e Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Sun, 12 Apr 2020 22:34:32 -0400 Subject: [PATCH] APIv4 - Fix setting offset with no limit The API treats 0 as "no limit" but mysql does not. This allows setting an offset with no limit but applying the maximum possible row count, as mysql does not allow LIMIT NULL. See https://stackoverflow.com/questions/255517/mysql-offset-infinite-rows --- Civi/Api4/Query/Api4SelectQuery.php | 3 ++- .../phpunit/api/v4/Action/ContactGetTest.php | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Civi/Api4/Query/Api4SelectQuery.php b/Civi/Api4/Query/Api4SelectQuery.php index 34c27ee671..75dd6d1487 100644 --- a/Civi/Api4/Query/Api4SelectQuery.php +++ b/Civi/Api4/Query/Api4SelectQuery.php @@ -241,7 +241,8 @@ class Api4SelectQuery extends SelectQuery { */ protected function buildLimit() { if (!empty($this->limit) || !empty($this->offset)) { - $this->query->limit($this->limit, $this->offset); + // If limit is 0, mysql will actually return 0 results. Instead set to maximum possible. + $this->query->limit($this->limit ?: '18446744073709551615', $this->offset); } } diff --git a/tests/phpunit/api/v4/Action/ContactGetTest.php b/tests/phpunit/api/v4/Action/ContactGetTest.php index 78d78eb375..e1be3ca566 100644 --- a/tests/phpunit/api/v4/Action/ContactGetTest.php +++ b/tests/phpunit/api/v4/Action/ContactGetTest.php @@ -58,4 +58,25 @@ class ContactGetTest extends \api\v4\UnitTestCase { $this->assertContains($del['id'], $contacts->column('id')); } + public function testGetWithLimit() { + $last_name = uniqid('getWithLimitTest'); + + $bob = Contact::create() + ->setValues(['first_name' => 'Bob', 'last_name' => $last_name]) + ->execute()->first(); + + $jan = Contact::create() + ->setValues(['first_name' => 'Jan', 'last_name' => $last_name]) + ->execute()->first(); + + $dan = Contact::create() + ->setValues(['first_name' => 'Dan', 'last_name' => $last_name]) + ->execute()->first(); + + $num = Contact::get()->setCheckPermissions(FALSE)->selectRowCount()->execute()->count(); + $this->assertCount($num - 1, Contact::get()->setCheckPermissions(FALSE)->setLimit(0)->setOffset(1)->execute()); + $this->assertCount($num - 2, Contact::get()->setCheckPermissions(FALSE)->setLimit(0)->setOffset(2)->execute()); + $this->assertCount(2, Contact::get()->setCheckPermissions(FALSE)->setLimit(2)->setOffset(0)->execute()); + } + } -- 2.25.1