diff --git a/src/Adapter/Driver/Pdo/Result.php b/src/Adapter/Driver/Pdo/Result.php index be729cda..870afa08 100644 --- a/src/Adapter/Driver/Pdo/Result.php +++ b/src/Adapter/Driver/Pdo/Result.php @@ -201,9 +201,11 @@ public function rewind() 'This result is a forward only result set, calling rewind() after moving forward is not supported' ); } - $this->currentData = $this->resource->fetch($this->fetchMode); - $this->currentComplete = true; - $this->position = 0; + if (! $this->currentComplete) { + $this->currentData = $this->resource->fetch($this->fetchMode); + $this->currentComplete = true; + } + $this->position = 0; } /** diff --git a/test/unit/Adapter/Driver/Pdo/ResultTest.php b/test/unit/Adapter/Driver/Pdo/ResultTest.php index 4ca159b3..f9ed2d5c 100644 --- a/test/unit/Adapter/Driver/Pdo/ResultTest.php +++ b/test/unit/Adapter/Driver/Pdo/ResultTest.php @@ -5,9 +5,11 @@ use Laminas\Db\Adapter\Driver\Pdo\Result; use Laminas\Db\Adapter\Exception\InvalidArgumentException; use PDO; +use PDOStatement; use PHPUnit\Framework\TestCase; use stdClass; +use function assert; use function uniqid; /** @@ -80,4 +82,66 @@ public function testFetchModeRange() self::assertEquals(11, $result->getFetchMode()); self::assertInstanceOf('stdClass', $result->current()); } + + public function testMultipleRewind() + { + $data = [ + ['test' => 1], + ['test' => 2], + ]; + $position = 0; + + $stub = $this->getMockBuilder('PDOStatement')->getMock(); + assert($stub instanceof PDOStatement); // to suppress IDE type warnings + $stub->expects($this->any()) + ->method('fetch') + ->will($this->returnCallback(function () use ($data, &$position) { + return $data[$position++]; + })); + $result = new Result(); + $result->initialize($stub, null); + + $result->rewind(); + $result->rewind(); + + $this->assertEquals(0, $result->key()); + $this->assertEquals(1, $position); + $this->assertEquals($data[0], $result->current()); + + $result->next(); + $this->assertEquals(1, $result->key()); + $this->assertEquals(2, $position); + $this->assertEquals($data[1], $result->current()); + } + + public function testMultipleRewindBuffered() + { + $data = [ + ['test' => 1], + ['test' => 2], + ]; + $position = 0; + + $stub = $this->getMockBuilder(PDOStatement::class)->getMock(); + assert($stub instanceof PDOStatement); // to suppress IDE type warnings + $stub->expects($this->any()) + ->method('fetch') + ->will($this->returnCallback(function () use ($data, &$position) { + return $data[$position++]; + })); + $result = new Result(); + $result->initialize($stub, null); + + $result->rewind(); + $result->rewind(); + + $this->assertEquals(0, $result->key()); + $this->assertEquals(1, $position); + $this->assertEquals($data[0], $result->current()); + + $result->next(); + $this->assertEquals(1, $result->key()); + $this->assertEquals(2, $position); + $this->assertEquals($data[1], $result->current()); + } } diff --git a/test/unit/ResultSet/AbstractResultSetTest.php b/test/unit/ResultSet/AbstractResultSetTest.php index 991cd4cf..8366cc1c 100644 --- a/test/unit/ResultSet/AbstractResultSetTest.php +++ b/test/unit/ResultSet/AbstractResultSetTest.php @@ -3,13 +3,17 @@ namespace LaminasTest\Db\ResultSet; use ArrayIterator; +use Laminas\Db\Adapter\Driver\Pdo\Result; use Laminas\Db\Adapter\Driver\ResultInterface; use Laminas\Db\ResultSet\AbstractResultSet; use Laminas\Db\ResultSet\Exception\InvalidArgumentException; use Laminas\Db\ResultSet\Exception\RuntimeException; +use PDOStatement; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use function assert; + class AbstractResultSetTest extends TestCase { /** @var MockObject */ @@ -266,4 +270,53 @@ public function testBufferIterations() $data = $resultSet->current(); self::assertEquals(3, $data['id']); } + + /** + * Test multiple iterations with buffer with multiple rewind() calls + * + * @group issue-6845 + */ + public function testMultipleRewindBufferIterations() + { + $resultSet = $this->getMockForAbstractClass(AbstractResultSet::class); + $result = new Result(); + $stub = $this->getMockBuilder(PDOStatement::class)->getMock(); + $data = new ArrayIterator([ + ['id' => 1, 'name' => 'one'], + ['id' => 2, 'name' => 'two'], + ['id' => 3, 'name' => 'three'], + ]); + assert($stub instanceof PDOStatement); // to suppress IDE type warnings + $stub->expects($this->any()) + ->method('fetch') + ->will($this->returnCallback(function () use ($data) { + $r = $data->current(); + $data->next(); + return $r; + })); + $result->initialize($stub, null); + $result->rewind(); + $result->rewind(); + $resultSet->initialize($result); + $resultSet->buffer(); + $resultSet->rewind(); + $resultSet->rewind(); + + $data = $resultSet->current(); + self::assertEquals(1, $data['id']); + $resultSet->next(); + $data = $resultSet->current(); + self::assertEquals(2, $data['id']); + + $resultSet->rewind(); + $resultSet->rewind(); + $data = $resultSet->current(); + self::assertEquals(1, $data['id']); + $resultSet->next(); + $data = $resultSet->current(); + self::assertEquals(2, $data['id']); + $resultSet->next(); + $data = $resultSet->current(); + self::assertEquals(3, $data['id']); + } }