<?php

final class PhabricatorQueryIterator extends PhutilBufferedIterator {

  private $query;
  private $pager;

  public function __construct(PhabricatorCursorPagedPolicyAwareQuery $query) {
    $this->query = $query;
  }

  protected function didRewind() {
    $this->pager = new AphrontCursorPagerView();
  }

  public function key() {
    return $this->current()->getID();
  }

  protected function loadPage() {
    if (!$this->pager) {
      return array();
    }

    $pager = clone $this->pager;
    $query = clone $this->query;

    $results = $query->executeWithCursorPager($pager);

    // If we got less than a full page of results, this was the last set of
    // results. Throw away the pager so we end iteration.
    if (count($results) < $pager->getPageSize()) {
      $this->pager = null;
    } else {
      $this->pager->setAfterID($pager->getNextPageID());
    }

    return $results;
  }

}

<?php

final class PhabricatorQueryIterator extends PhutilBufferedIterator {

  private $query;
  private $pager;

  public function __construct(PhabricatorCursorPagedPolicyAwareQuery $query) {
    $this->query = $query;
  }

  protected function didRewind() {
    $this->pager = new AphrontCursorPagerView();
  }

  public function key() {
    return $this->current()->getID();
  }

  protected function loadPage() {
    if (!$this->pager) {
      return array();
    }

    $pager = clone $this->pager;
    $query = clone $this->query;

    $results = $query->executeWithCursorPager($pager);

    // If we got less than a full page of results, this was the last set of
    // results. Throw away the pager so we end iteration.
    if (!$pager->getHasMoreResults()) {
      $this->pager = null;
    } else {
      $this->pager->setAfterID($pager->getNextPageID());
    }

    return $results;
  }

}

Fix loop in QueryIterator when row count is an exact multiple of page size
Fix loop in QueryIterator when row count is an exact multiple of page size

Summary: Ref T13152. The pager does a bit of magic here and doesn't populate `nextPageID` when it knows it got an exact final page. The logic misfired in this case and sent us back to the start.

Test Plan:
  - Set page size to 1 to guarantee rows were an exact multiple of page size.
  - Ran `rebuild-identities` (I no-op'd the actual logic to make it faster).
  - Before: looped forever.
  - After: clean exit after processing everything.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13152

Differential Revision: https://secure.phabricator.com/D19479
