Просмотр исходного кода

Fix ZF-9252: SqlSrv driver doesn't handle tablename.fieldname in order by clause when using limit

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@21196 44c647ce-9c0f-0410-b52a-842ac1e357ba
rob 16 лет назад
Родитель
Сommit
9d9f5e1101
2 измененных файлов с 66 добавлено и 17 удалено
  1. 23 17
      library/Zend/Db/Adapter/Sqlsrv.php
  2. 43 0
      tests/Zend/Db/Adapter/SqlsrvTest.php

+ 23 - 17
library/Zend/Db/Adapter/Sqlsrv.php

@@ -605,23 +605,29 @@ class Zend_Db_Adapter_Sqlsrv extends Zend_Db_Adapter_Abstract
             throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");
         }
 
-        $orderby = stristr($sql, 'ORDER BY');
-        if ($orderby !== false) {
-            $sort  = (stripos($orderby, ' desc') !== false) ? 'desc' : 'asc';
-            $order = str_ireplace('ORDER BY', '', $orderby);
-            $order = trim(preg_replace('/\bASC\b|\bDESC\b/i', '', $order));
-        }
-
-        $sql = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . ($count+$offset) . ' ', $sql);
-
-        $sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl';
-        if ($orderby !== false) {
-            $sql .= ' ORDER BY ' . $order . ' ';
-            $sql .= (stripos($sort, 'asc') !== false) ? 'DESC' : 'ASC';
-        }
-        $sql .= ') AS outer_tbl';
-        if ($orderby !== false) {
-            $sql .= ' ORDER BY ' . $order . ' ' . $sort;
+        if ($offset == 0) {
+            $sql = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . $count . ' ', $sql);
+        } else {
+            $orderby = stristr($sql, 'ORDER BY');
+            if ($orderby !== false) {
+                $sort  = (stripos($orderby, ' desc') !== false) ? 'desc' : 'asc';
+                $order = str_ireplace('ORDER BY', '', $orderby);
+                $order = trim(preg_replace('/\bASC\b|\bDESC\b/i', '', $order));
+            }
+    
+            $sql = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . ($count+$offset) . ' ', $sql);
+    
+            $sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl';
+            if ($orderby !== false) {
+                $innerOrder = preg_replace('/\".*\".\"(.*)\"/i', '"inner_tbl"."$1"', $order);
+                $sql .= ' ORDER BY ' . $innerOrder . ' ';
+                $sql .= (stripos($sort, 'asc') !== false) ? 'DESC' : 'ASC';
+            }
+            $sql .= ') AS outer_tbl';
+            if ($orderby !== false) {
+                $outerOrder = preg_replace('/\".*\".\"(.*)\"/i', '"outer_tbl"."$1"', $order);
+                $sql .= ' ORDER BY ' . $outerOrder . ' ' . $sort;
+            }
         }
 
         return $sql;

+ 43 - 0
tests/Zend/Db/Adapter/SqlsrvTest.php

@@ -430,6 +430,49 @@ class Zend_Db_Adapter_SqlsrvTest extends Zend_Db_Adapter_TestCommon
 
         $this->assertTrue($db->setTransactionIsolationLevel(), "Setting to default should work by passsing null or nothing");
     }
+    
+    /**
+     * @group ZF-9252
+     * @see zf-trunk/tests/Zend/Db/Adapter/Zend_Db_Adapter_TestCommon#testAdapterLimit()
+     */
+    public function testAdapterLimit()
+    {
+    	parent::testAdapterLimit();
+
+        $products = $this->_db->quoteIdentifier('zfproducts');
+        $product_id = $this->_db->quoteIdentifier('product_id');
+
+        $sql = $this->_db->limit("SELECT * FROM $products ORDER BY $products.$product_id", 1);
+
+        $stmt = $this->_db->query($sql);
+        $result = $stmt->fetchAll();
+        $this->assertEquals(1, count($result),
+            'Expecting row count to be 1');
+        $this->assertEquals(1, $result[0]['product_id'],
+            'Expecting to get product_id 1');
+
+    }
+    
+    /**
+     * @group ZF-9252
+     * @see zf-trunk/tests/Zend/Db/Adapter/Zend_Db_Adapter_TestCommon#testAdapterLimitOffset()
+     */
+    public function testAdapterLimitOffset()
+    {
+    	parent::testAdapterLimitOffset();
+    	
+        $products = $this->_db->quoteIdentifier('zfproducts');
+        $product_id = $this->_db->quoteIdentifier('product_id');
+
+        $sql = $this->_db->limit("SELECT * FROM $products ORDER BY $products.$product_id", 1, 1);
+
+        $stmt = $this->_db->query($sql);
+        $result = $stmt->fetchAll();
+        $this->assertEquals(1, count($result),
+            'Expecting row count to be 1');
+        $this->assertEquals(2, $result[0]['product_id'],
+            'Expecting to get product_id 2');
+    }    
 
     public function getDriver()
     {