備忘錄_20160105(定位) 修改 回首頁

程式 2024-09-24 10:10:02 1727143802 100
資料庫常用類別設計 MSSQL,MicrosoftSQLServer,PHP,sqlsrv or odbc

資料庫常用類別設計 MSSQL,MicrosoftSQLServer,PHP,sqlsrv or odbc

<?php
  
  { // 範例
  
    //
    // 範例 insUpdDel
    //
    // $oMSSQL=new CMSSQL_v3_sqlsrv(); 或 $oMSSQL=new CMSSQL_v3_odbc();
    // $oStatement=$oMSSQL->insUpdDel('default', "insert into tb1(nc1) values('用JSON測試。')");
    //
    // echo '------html------<br>';
    // echo 'booInsUpdDel:' . ($oStatement->booInsUpdDel ? 'true' : 'false') . '<br>';
    // echo 'booSuccess:' . ($oStatement->booSuccess ? 'true' : 'false') . '<br>';
    // echo 'strErrorMessage:' . htmlspecialchars($oStatement->strErrorMessage) . '<br>';
    // echo 'iAffectedRows:' . $oStatement->iAffectedRows . '<br>';
    //
    // echo '------json------<br>';
    // echo json_encode($oStatement, JSON_UNESCAPED_UNICODE);
    //
    
    //
    // 範例 bigQuery
    //
    // $oMSSQL=new CMSSQL_v3_sqlsrv(); 或 $oMSSQL=new CMSSQL_v3_odbc();
    // $oStatement=$oMSSQL->bigQuery('default', "select 1 as x,* from tb1");
    //
    // echo '------html------<br>';
    // echo 'booInsUpdDel:' . ($oStatement->booInsUpdDel ? 'true' : 'false') . '<br>';
    // echo 'booSuccess:' . ($oStatement->booSuccess ? 'true' : 'false') . '<br>';
    // echo 'strErrorMessage:' . htmlspecialchars($oStatement->strErrorMessage) . '<br>';
    // echo 'iResultAmount:' . $oStatement->iResultAmount . '<br>';
    // echo 'oaUnitResult:' . htmlspecialchars(json_encode($oStatement->oaUnitResult, JSON_UNESCAPED_UNICODE)) . '<br>';
    //
    // echo '------json------<br>';
    // echo json_encode($oStatement, JSON_UNESCAPED_UNICODE);
    //
  }
  
  { // [customvalue]
    
    // [customvalue] for sqlsrv
    $aryConn_db1_20240920153500=array('ServerName'=>'192.168.0.99,1433', 'ConnInfo'=>['Database'=>'db1', 'UID'=>'username', 'PWD'=>'password', 'CharacterSet'=>'UTF-8', 'LoginTimeout'=>180]);
    $aryConn_db2_20240920153600=array('ServerName'=>'192.168.0.88,1433', 'ConnInfo'=>['Database'=>'db2', 'UID'=>'username', 'PWD'=>'password', 'CharacterSet'=>'UTF-8', 'LoginTimeout'=>180]);

    // [customevalue] for odbc
    $aryConn_db1_20240923110600=array('dsn'=>'Driver={FreeTDS};Server=192.168.0.99;Port=1433;Database=db1;ClientCharset=UTF-8;TDS_Version=7.4;', 'uid'=>'username', 'pwd'=>'password');
    $aryConn_db2_20240924100600=array('dsn'=>'Driver={FreeTDS};Server=192.168.0.88;Port=1433;Database=db2;ClientCharset=UTF-8;TDS_Version=7.4;', 'uid'=>'username', 'pwd'=>'password');
    
  }
  
  class CSQLUnitResult_v3
  {
    public $straFieldName=array();
    public $booaTextType=array();
    public $iRows=0;
    public $iCols=0;
    public $aryRawData=array();
    
    public function getVal($iRow, $strFieldName)
    {
      $iCol=array_search($strFieldName, $this->straFieldName);
      if($iCol===false) { return 'field name not found!'; }
      if($iRow>=$this->iRows) { return 'row index out of range!'; }
      return $this->aryRawData[$iRow][$iCol];
    }
  }
  
  class CSQLStatement_v3
  {
    public $booInsUpdDel=false; // 增修刪=true, 大查詢=false
    
    public $booSuccess=false;
    public $strErrorMessage='';
    
    // 增修刪↓
    public $iAffectedRows=0;
    
    // 大查詢↓
    public $iResultAmount=0;
    public $oaUnitResult=array(); // 裝載 CSQLUnitResult_v3 的陣列,用 array_push()
  }
  
  class CMSSQL_v3_sqlsrv
  {
    private function getAryConnection($strWho)
    {
      global $aryConn_db1_20240920153500, $aryConn_db2_20240920153600;
      if($strWho=='db2') { return $aryConn_db2_20240920153600; }
      else               { return $aryConn_db1_20240920153500; }
    }
    
    // 參數正規化,避免 SQL Injection
    public function getStrNum($value) { return strval(floatval($value)); }
    public function getStrNormalizedString($value) { return str_replace("'","''",$value); }
    public function getStrAnsiTxt($value) { return "'" . $this->getStrNormalizedString($value) . "'"; }
    public function getStrUniTxt($value) { return "N'" . $this->getStrNormalizedString($value) . "'"; }
    public function getStrAnsiLikeTxt($value) { return "'" . '%' . $this->getStrNormalizedString($value) . '%' . "'"; }
    public function getStrUniLikeTxt($value) { return "N'" . '%' . $this->getStrNormalizedString($value) . '%' . "'"; }
    public function getStrFreeText($value) { return $value; }
    
    public function insUpdDel($strWho, $strSQL, $iQueryTimeout=600)
    {
      $oStatement=new CSQLStatement_v3();
      $oStatement->booInsUpdDel=true;
      
      while(true)
      {
        // 連線到資料庫
        $aryConn=$this->getAryConnection($strWho);
        $oConn=sqlsrv_connect($aryConn['ServerName'], $aryConn['ConnInfo']);
        if($oConn==false)
        {
          $oStatement->booSuccess=false;
          $oStatement->strErrorMessage='資料庫連線失敗!ErrMsg:' . print_r(sqlsrv_errors(),true);
          break;
        }
        
        while(true)
        {
          // 執行 SQL 指令劇本
          $oStmt=sqlsrv_query($oConn, $strSQL, NULL, array('QueryTimeout'=>$iQueryTimeout));
          if($oStmt===false)
          {
            $oStatement->booSuccess=false;
            $oStatement->strErrorMessage='資料庫異動失敗!ErrMsg:' . print_r(sqlsrv_errors(),true);
            break;
          }
          
          // 取得資訊
          $oStatement->booSuccess=true;
          $oStatement->iAffectedRows=sqlsrv_rows_affected($oStmt);
          
          // 釋放資源
          sqlsrv_free_stmt($oStmt);
          break;
        }
        
        // 釋放連線
        sqlsrv_close($oConn);
        break;
      }
      
      return $oStatement;
    }
    
    public function bigQuery($strWho, $strSQL, $iQueryTimeout=600)
    {
      $oStatement=new CSQLStatement_v3();
      $oStatement->booInsUpdDel=false;
      
      while(true)
      {
        // 連線到資料庫
        $aryConn=$this->getAryConnection($strWho);
        $oConn=sqlsrv_connect($aryConn['ServerName'], $aryConn['ConnInfo']);
        if($oConn==false)
        {
          $oStatement->booSuccess=false;
          $oStatement->strErrorMessage='資料庫連線失敗!ErrMsg:' . print_r(sqlsrv_errors(),true);
          break;
        }
        
        while(true)
        {
          // 執行 SQL 指令劇本
          $oStmt=sqlsrv_query($oConn, $strSQL, NULL, array('QueryTimeout'=>$iQueryTimeout));
          if($oStmt===false)
          {
            $oStatement->booSuccess=false;
            $oStatement->strErrorMessage='資料庫查詢失敗!ErrMsg:' . print_r(sqlsrv_errors(),true);
            break;
          }
          
          // 逐個結果集檢視
          $oStatement->booSuccess=true;
          while(true)
          {
            // 新增一個單元
            $oStatement->iResultAmount++;
            $oUnit=new CSQLUnitResult_v3();
            
            $oUnit->iCols=sqlsrv_num_fields($oStmt);
            $aryMetaData=sqlsrv_field_metadata($oStmt);
            for($i=0; $i<$oUnit->iCols; $i++)
            {
              $oUnit->straFieldName[]=$aryMetaData[$i]['Name'];
              $oUnit->booaTextType[]=in_array($aryMetaData[$i]['Type'], array(-10,-9,-8,-1,1,12));
            }
            while($oStatementow=sqlsrv_fetch_array($oStmt, SQLSRV_FETCH_NUMERIC))
            {
              $oUnit->iRows++;
              $oUnit->aryRawData[]=$oStatementow;
            }
            $oStatement->oaUnitResult[]=$oUnit;
            
            $oNextResult=sqlsrv_next_result($oStmt);
            if($oNextResult===null) { break; } // 沒有資料集了。
            if($oNextResult===false) // 發生錯誤!
            {
              $oStatement->booSuccess=false;
              $oStatement->strErrorMessage=$oStatement->strErrorMessage . '。資料庫查詢意外!ErrMsg:' . print_r(sqlsrv_errors(),true);
              break;
              // 2015-08-18 
              // 實務經驗,有錯誤發生之後,後面的結果記錄集通通都消失,不會回饋!
              // 所以有可能會漏掉錯誤結果集之後的成功結果集喔!
              //
              // 2023-02-09 
              // 因此,最好的實作就是在劇本中用(transaction),有任何問題,全部復原(rollback)!
            }
          }
          
          // 釋放資源
          sqlsrv_free_stmt($oStmt);
          break;
        }
        
        // 釋放連線
        sqlsrv_close($oConn);
        break;
      }
      
      return $oStatement;
    }
    
  }
  
  class CMSSQL_v3_odbc
  {
    private function getAryConnection($strWho)
    {
      global $aryConn_db1_20240923110600, $aryConn_db2_20240924100600;
      if($strWho=='db2') { return $aryConn_db2_20240924100600; }
      else               { return $aryConn_db1_20240923110600; }
    }
    
    // 參數正規化,避免 SQL Injection
    public function getStrNum($value) { return strval(floatval($value)); }
    public function getStrNormalizedString($value) { return str_replace("'","''",$value); }
    public function getStrAnsiTxt($value) { return "'" . $this->getStrNormalizedString($value) . "'"; }
    public function getStrUniTxt($value) { return "N'" . $this->getStrNormalizedString($value) . "'"; }
    public function getStrAnsiLikeTxt($value) { return "'" . '%' . $this->getStrNormalizedString($value) . '%' . "'"; }
    public function getStrUniLikeTxt($value) { return "N'" . '%' . $this->getStrNormalizedString($value) . '%' . "'"; }
    public function getStrFreeText($value) { return $value; }
    
    public function insUpdDel($strWho, $strSQL)
    {
      $oStatement=new CSQLStatement_v3();
      $oStatement->booInsUpdDel=true;
      
      while(true)
      {
        // 連線到資料庫
        $aryConn=$this->getAryConnection($strWho);
        $oConn=odbc_connect($aryConn['dsn'], $aryConn['uid'], $aryConn['pwd']);
        if($oConn==false)
        {
          $oStatement->booSuccess=false;
          $oStatement->strErrorMessage='資料庫連線失敗!';
          break;
        }
        
        while(true)
        {
          // 執行 SQL 指令劇本
          $oStmt=odbc_exec($oConn, $strSQL);
          if($oStmt===false)
          {
            $oStatement->booSuccess=false;
            $oStatement->strErrorMessage='資料庫異動失敗!ErrMsg:' . odbc_errormsg($oConn);
            break;
          }
          
          // 取得資訊
          $oStatement->booSuccess=true;
          $oStatement->iAffectedRows=odbc_num_rows($oStmt);
          
          // 釋放資源
          odbc_free_result($oStmt);
          break;
        }
        
        // 釋放連線
        odbc_close($oConn);
        break;
      }
      
      return $oStatement;
    }
    
    public function bigQuery($strWho, $strSQL)
    {
      // 注意,語法中只能有一個 go 指令。
      //
      // 注意,若你的語法有三個 select,但若只有兩個有傳回資料,則只會出現兩個結果集!!!
      // odbc 這個行為跟 sqlsrv 的行為,完全不同,千萬要留意!
      
      $oStatement=new CSQLStatement_v3();
      $oStatement->booInsUpdDel=false;
      
      while(true)
      {
        // 連線到資料庫
        $aryConn=$this->getAryConnection($strWho);
        $oConn=odbc_connect($aryConn['dsn'], $aryConn['uid'], $aryConn['pwd']);
        if($oConn==false)
        {
          $oStatement->booSuccess=false;
          $oStatement->strErrorMessage='資料庫連線失敗!';
          break;
        }
        
        while(true)
        {
          // 執行 SQL 指令劇本
          $oStmt=odbc_exec($oConn, $strSQL);
          if($oStmt===false)
          {
            $oStatement->booSuccess=false;
            $oStatement->strErrorMessage='資料庫查詢失敗!ErrMsg:' . odbc_errormsg($oConn);
            break;
          }
          
          // 逐個結果集檢視
          $oStatement->booSuccess=true;
          while(true)
          {
            // 新增一個單元
            $oStatement->iResultAmount++;
            $oUnit=new CSQLUnitResult_v3();
            
            $oUnit->iCols=odbc_num_fields($oStmt);
            for($i=0; $i<$oUnit->iCols; $i++)
            {
              $oUnit->straFieldName[]=odbc_field_name($oStmt, $i+1);
              $oUnit->booaTextType[]=in_array(odbc_field_type($oStmt, $i+1), array('text','ntext','char','nchar','varchar','nvarchar'));
            }
            
            $aryBuffer=array();
            while($booSuccess=odbc_fetch_into($oStmt, $aryBuffer))
            {
              $oUnit->iRows++;
              $oUnit->aryRawData[]=$aryBuffer;
            }
            $oStatement->oaUnitResult[]=$oUnit;
            
            $oNextResult=odbc_next_result($oStmt);
            if($oNextResult===false) { break; }
          }
          
          // 釋放資源
          odbc_free_result($oStmt);
          break;
        }
        
        // 釋放連線
        odbc_close($oConn);
        break;
      }
      
      return $oStatement;
    }
    
  }
  
?>