(二)關於ThinkPHP2.1版本操做MSSQL類的BUG--selec查詢只得出1條記錄

BUG:Model類的select方法默認只返回1條記錄php

TP的手冊中寫的是select方法返回的是所有的記錄,但我在實際操做中,返回的只有1條記錄,咱們再次進行源碼的分析。sql

(1)Action中的代碼以下:thinkphp

 

  
  
  
  
  1. $operaInfo = new Model("tbloperainfo"); 
  2. $list = $operaInfo->select(); 

(2)根據代碼咱們進入Model類的select方法,在select方法中又調用了Db類的select方法:數組

  
  
  
  
  1. $resultSet = $this->db->select($options); 

(3)select方法中有以下的代碼片斷,對查詢的sql進行了處理:ide

  
  
  
  
  1. $sql   = str_replace
  2.             array('%TABLE%','%DISTINCT%','%FIELDS%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%'), 
  3.             array
  4.                 $this->parseTable($options['table']), 
  5.                 $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), 
  6.                 $this->parseField(isset($options['field'])?$options['field']:'*'), 
  7.                 $this->parseJoin(isset($options['join'])?$options['join']:''), 
  8.                 $this->parseWhere(isset($options['where'])?$options['where']:''), 
  9.                 $this->parseGroup(isset($options['group'])?$options['group']:''), 
  10.                 $this->parseHaving(isset($options['having'])?$options['having']:''), 
  11.                 $this->parseOrder(isset($options['order'])?$options['order']:''), 
  12.                 $this->parseLimit(isset($options['limit'])?$options['limit']:''
  13.             ),$this->selectSql); 
  14.         $sql   .= $this->parseLock(isset($options['lock'])?$options['lock']:false); 
  15.         return $this->query($sql); 

在處理的時候調用了parseLimit方法,因爲面向對象的多態性,這個方法應該是在DbMssql中的parseLimit方法。咱們看下該方法的參數:isset($options['limit'])?$options['limit']:'' 這個表達式結果應該爲空字符串'',由於咱們在調用Model類的select方法的時候沒有傳任何參數。this

咱們進入DbMssql看下代碼以下:spa

  
  
  
  
  1. public function parseLimit($limit) { 
  2.         if(empty($limit)) $limit=1; 
  3.         $limit  =   explode(',',$limit); 
  4.         if(count($limit)>1) 
  5.             $limitStr   =   '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')'
  6.         else 
  7.             $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")"
  8.         return $limitStr
  9.     } 

(4)在parseLimit方法中,第一步將$limit賦值爲1;第二部將$limit拆分爲數組;第三部判斷數組的元素個數後執行了以下的代碼:對象

$limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")"; 字符串

在這裏咱們能夠看出$limitStr的具體值爲:'(T1.ROW_NUMBER BETWEEN 1 AND 1)'get

好,咱們繼續跟蹤源碼。

(5)第3步對$selectSql處理後,調用了DbMssql類的query方法,在該方法中又調用了getAll方法將查詢的結果存入$result數組,緊接着將$result一層層返回。

(6)好,到此爲止執行流程已經所有結束。咱們看下具體執行的SQL,以下:

  
  
  
  
  1. SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER ( ORDER BY agentid) AS ROW_NUMBER FROM (SELECT * FROM tblagentinfo) AS thinkphp) AS T1 WHERE (T1.ROW_NUMBER BETWEEN 1 AND 1) 

看下執行的SQL,發現引發這個BUG的緣由就是: (T1.ROW_NUMBER BETWEEN 1 AND 1) 這個SQL片斷。

(7)緣由找到了,該如何處理呢?

咱們確定是在DbMssql類的parseLimit方法下手,由於咱們須要查詢全部的記錄,所以該方法返回的值最好是爲 '' 。咱們將parseLimit方法的第一行代碼修改成以下的代碼:

  
  
  
  
  1. if(emptyempty($limit)) { 
  2.      return $limit

就是若是$limit爲空,直接返回。修改後刷新下頁面發現報錯了,看了執行的SQL以下:

  
  
  
  
  1. SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER ( ORDER BY agentid) AS ROW_NUMBER FROM (SELECT * FROM tblagentinfo) AS thinkphp) AS T1 WHERE 

發現SQL到WHERE關鍵字就沒了,咱們看下DbMssql中$selectSql的定義:

  
  
  
  
  1. protected $selectSql  =     'SELECT T1.* FROM (SELECT ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER, thinkphp.* FROM (SELECT %DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 WHERE %LIMIT%' 

再結合parseLimit方法中的代碼,具體處理方法以下:

1.將SQL中的WHERE刪掉

2.在parseLimit中將代碼修改以下:

  
  
  
  
  1. if(count($limit)>1) 
  2.            $limitStr    =   ' WHERE (T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')'
  3.     else 
  4.            $limitStr = ' WHERE (T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")"

便是將WHERE直接放到$limitStr中,這樣就OK了。

相關文章
相關標籤/搜索