diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 9442b55f87d..cbf0cddb6d2 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -7,6 +7,7 @@ Yii Framework 2 Change Log - Bug #17413, #17418, #17426, #17431: Fixed MSSQL tests (alexkart) - Bug #17420: Fixed loading of column default values for MSSQL (alexkart) - Bug #17395: Fixed issues with actions that contain underscores in their names (alexkart) +- Bug #10023: Fixed MSSQL "There are no more rows in the active result set" exception when using `each()` and `batch()` (alexkart) 2.0.22 July 02, 2019 diff --git a/framework/db/BatchQueryResult.php b/framework/db/BatchQueryResult.php index 131e6de5034..eba90c2cd7c 100644 --- a/framework/db/BatchQueryResult.php +++ b/framework/db/BatchQueryResult.php @@ -66,7 +66,11 @@ class BatchQueryResult extends BaseObject implements \Iterator * @var string|int the key for the current iteration */ private $_key; - + /** + * @var string MSSQL exception that is thrown when last batch size less than specified batch size + * @see https://github.com/yiisoft/yii2/issues/10023 + */ + private $mssqlNoMoreRowsErrorMessage = 'SQLSTATE[IMSSP]: There are no more rows in the active result set. Since this result set is not scrollable, no more data may be retrieved.'; /** * Destructor. @@ -131,6 +135,7 @@ public function next() /** * Fetches the next batch of data. * @return array the data fetched + * @throws Exception */ protected function fetchData() { @@ -138,13 +143,32 @@ protected function fetchData() $this->_dataReader = $this->query->createCommand($this->db)->query(); } + $rows = $this->getRows(); + + return $this->query->populate($rows); + } + + /** + * Reads and collects rows for batch + * @since 2.0.23 + * @return array + */ + protected function getRows() + { $rows = []; $count = 0; - while ($count++ < $this->batchSize && ($row = $this->_dataReader->read())) { - $rows[] = $row; + + try { + while ($count++ < $this->batchSize && ($row = $this->_dataReader->read())) { + $rows[] = $row; + } + } catch (\PDOException $e) { + if ($e->getMessage() !== $this->mssqlNoMoreRowsErrorMessage) { + throw $e; + } } - return $this->query->populate($rows); + return $rows; } /** diff --git a/tests/framework/db/mssql/BatchQueryResultTest.php b/tests/framework/db/mssql/BatchQueryResultTest.php index ca123e59447..492373d72c1 100644 --- a/tests/framework/db/mssql/BatchQueryResultTest.php +++ b/tests/framework/db/mssql/BatchQueryResultTest.php @@ -7,8 +7,6 @@ namespace yiiunit\framework\db\mssql; -use yii\db\BatchQueryResult; - /** * @group db * @group mssql @@ -16,37 +14,4 @@ class BatchQueryResultTest extends \yiiunit\framework\db\BatchQueryResultTest { public $driverName = 'sqlsrv'; - private $noMoreRowsErrorMessage = 'SQLSTATE[IMSSP]: There are no more rows in the active result set. Since this result set is not scrollable, no more data may be retrieved.'; - - protected function getAllRowsFromBach(BatchQueryResult $batch) - { - $allRows = []; - try { - foreach ($batch as $rows) { - $allRows = array_merge($allRows, $rows); - } - } catch (\PDOException $e) { - if ($e->getMessage() !== $this->noMoreRowsErrorMessage) { - throw $e; - } - } - - return $allRows; - } - - protected function getAllRowsFromEach(BatchQueryResult $each) - { - $allRows = []; - try { - foreach ($each as $index => $row) { - $allRows[$index] = $row; - } - } catch (\PDOException $e) { - if ($e->getMessage() !== $this->noMoreRowsErrorMessage) { - throw $e; - } - } - - return $allRows; - } }