phpsql-serveryiicgridviewcsqldataprovider

Yii CSqlDataProvider() and MSSQL - last page bug


I'm using Yii 1.1.16 and CSqlDataProvider() to display data in CGridView. When go to last page I get last PageSize count records, instead number of records on last page. For example, I have grid with 12 record and PageSize set to 10, which means I have 2 pages, so on page 1, I get records from 1 - 10, but on page 2 (last page) I get records 3 - 12!

This are values I get on each page

//on page 1
$dataProvider->getPagination()->getPageCount(); //2
$dataProvider->getPagination()->currentPage; //0
$dataProvider->getPagination()->offset; //0

//on page 2
$dataProvider->getPagination()->getPageCount(); //2
$dataProvider->getPagination()->currentPage; //1
$dataProvider->getPagination()->offset; //10

As you can see, this is values I should get on pages, and data displayed should be correct,but aren't.

I intentionally wrote Yii version, because this was working before Yii upgrade from 1.1.8

One more thing, I'm using MSSQL (Microsoft SQL) database for providing data


Solution

  • Seems like this is Yii framework issue with MSSQL and here is one of solutions, overriding CSqlDataProvider

    class MSSqlDataProvider extends CSqlDataProvider
    {
    
        /**
         * Fetches the data from the persistent data storage.
         * @return array list of data items
         */
        protected function fetchData()
        {
            $sql = $this->sql;
            $db = $this->db === null ? Yii::app()->db : $this->db;
            $db->active = true;
    
            if (($sort = $this->getSort()) !== false) {
                $order = $sort->getOrderBy();
                if (!empty($order)) {
                    if (preg_match('/\s+order\s+by\s+[\w\s,]+$/i', $sql))
                        $sql.=', ' . $order;
                    else
                        $sql.=' ORDER BY ' . $order;
                }
            }
    
            if (($pagination = $this->getPagination()) !== false) {
                $pagination->setItemCount($this->getTotalItemCount());
                $limit = $pagination->getLimit();
                $offset = $pagination->getOffset();
    
                // update limit to the correct value for the last page 
                if ($offset + $limit > $pagination->getItemCount())
                    $limit = $pagination->getItemCount() - $offset;
    
                $sql = $db->getCommandBuilder()->applyLimit($sql, $limit, $offset);
            }
    
            $command = $db->createCommand($sql);
            foreach ($this->params as $name => $value)
                $command->bindValue($name, $value);
    
            return $command->queryAll();
        }
    
    }
    

    Thanks to this post.