2011-09-12 64 views
4

這是我寫的一個Zend_Application_Resource,用於在部署中進行更改時自動更新模式。如何使用Zend_Db_Adapter對每個「查詢」調用運行多個SQL查詢?

<?php 

/** 
* Makes sure the current schema version matches what we're expecting for this 
* particular version of the application. 
* 
* The version of the database is compared against the value configured in 
* application.ini. SQL scripts corresponding to versions between the database 
* version's and the current local SQL scripts are run against the database to 
* get things up to date. 
* 
* @copyright 2011 Case Western Reserve University, College of Arts and Sciences 
* @author Billy O'Neal III ([email protected]) 
*/ 
class Cas_Application_Resource_Schema extends Zend_Application_Resource_ResourceAbstract 
{ 
    /** 
    * Creates an array of filepaths corresponding to the scripts that need 
    * to run. 
    * 
    * @param int $from 
    * @param int $to 
    * @return array 
    */ 
    private function GetScriptsToRun($from, $to) 
    { 
     $application = APPLICATION_PATH . '/configs/sql/'; 
     $result = array(); 
     for($cur = $from + 1; $cur <= $to; $cur++) 
     { 
      $result[] = "{$application}{$cur}.sql"; 
     } 
     return $result; 
    } 

    /** 
    * Returns the version the application is locally configured to expect. 
    * 
    * @return int 
    */ 
    private function GetLocalVersion() 
    { 
     $options = $this->getOptions(); 
     $version = (int)$options['version']; 
     return $version; 
    } 

    /** 
    * Returns the version the database thinks it is. 
    * 
    * @return int 
    */ 
    private function GetDbVersion() 
    { 
     $adapter = Zend_Db_Table::getDefaultAdapter(); 
     $metadataTable = new Cas_Model_Table_Metadata; 
     $verQuery = $metadataTable->select()->from($metadataTable, array('Value')); 
     $verQuery->where("{$adapter->quoteIdentifier('Key')} = ?", 'Version'); 
     $dbVersion = $adapter->fetchOne($verQuery); 
     return (int)$dbVersion; 
    } 

    /** 
    * Runs the specified filepath's file contents as a SQL script. 
    * 
    * @param string $scriptPath 
    */ 
    private function RunSqlScript($scriptPath) 
    { 
     $adapter = Zend_Db_Table::getDefaultAdapter(); 
     $contents = file_get_contents($scriptPath); 
     $adapter->query($contents); 
    } 

    /** 
    * Updates the version number in the database to match the version 
    * specified in the local configuration file. 
    */ 
    private function UpdateVersion() 
    { 
     $metadataTable = new Cas_Model_Table_Metadata; 
     $metadataTable->delete(array("{$metadataTable->getAdapter()->quoteIdentifier('Key')} = ?" => 'Version')); 
     $metadataTable->insert(array('Version' => $this->GetLocalVersion())); 
    } 

    /** 
    * Performs the actual schema checks. 
    */ 
    public function init() 
    { 
     //We depend on the database being connected. 
     $this->getBootstrap()->bootstrap('db'); 
     $local = $this->GetLocalVersion(); 
     $remote = $this->GetDbVersion(); 
     if ($local < $remote) 
     { 
      throw new Exception('Database version is newer than local version.'); 
     } 
     else if ($remote < $local) 
     { 
      $scripts = self::GetScriptsToRun($remote, $local); 
      foreach($scripts as $script) 
      { 
       $this->RunSqlScript($script); 
      } 
      $this->UpdateVersion(); 
     } 
    } 
} 

這將失敗,因爲有問題的腳本(例如CONFIGS/SQL/1.SQL,CONFIGS/SQL/2.SQL等)包含多個SQL語句,通過分離; S,與消息類似:

Zend_Db_Statement_Mysqli_Exception: Mysqli prepare error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ';'

回答

4

Zend_Db_Adapter不支持multi_query()

您有解決方法的選擇:

  • 呼叫$adapter->getConnection(),這將返回底層的mysqli資源的實例。您可以撥打此資源的multi_query()方法。

  • 將文件的內容拆分爲單個SQL語句的數組,併爲每個語句調用$adapter->query()Be careful about edge cases.

  • 使用shell_exec()調用mysql命令行工具的子進程來處理SQL腳本。

+0

:感嘆:......這很令人沮喪。 +1。 –

+0

那麼,這會導致另一個問題 - > http://stackoverflow.com/questions/7395326/how-do-i-ensure-i-caught-all-errors-from-mysqlimulti-query ..我不能使用' shell_exec'因爲PHP二進制文件在PHP服務器上不可用,而且我沒有深入SQL解析自己。 –