Changeset 5082

Show
Ignore:
Timestamp:
10/13/08 21:59:17 (9 months ago)
Author:
adrive
Message:

[1.0, 1.1] Fixes #1463: Updated Doctrine_Adapter_Oracle. Thanks to vadik56..

Location:
branches/1.0/lib/Doctrine/Adapter
Files:
1 added
1 modified

Legend:

Unmodified
Added
Removed
  • branches/1.0/lib/Doctrine/Adapter/Oracle.php

    r4520 r5082  
    11<?php 
    22/* 
    3  *  $Id: Mock.php 1080 2007-02-10 18:17:08Z romanb $ 
     3 *  $Id$ 
    44 * 
    55 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
     
    2929 * @link        www.phpdoctrine.org 
    3030 * @since       1.0 
    31  * @version     $Revision: 1080 $ 
     31 * @version     $Revision$ 
    3232 */ 
    33 class Doctrine_Adapter_Oracle extends Doctrine_Adapter 
    34 { 
    35     /** 
    36      * User-provided configuration. 
    37      * 
    38      * Basic keys are: 
    39      * 
    40      * username => (string) Connect to the database as this username. 
    41      * password => (string) Password associated with the username. 
    42      * dbname   => Either the name of the local Oracle instance, or the 
    43      *             name of the entry in tnsnames.ora to which you want to connect. 
    44      * 
    45      * @var array 
    46      */ 
    47     protected $_config = array( 
    48         'dbname'       => null, 
    49         'username'     => null, 
    50         'password'     => null, 
    51     ); 
    52  
    53     /** 
    54      * Current execute mode 
    55      * 
    56      * @var integer 
    57      */ 
    58     protected $_executeMode = OCI_COMMIT_ON_SUCCESS; 
    59  
    60     /** 
    61      * $config is an array of key/value pairs containing configuration 
    62      * options.  These options are common to most adapters: 
    63      * 
    64      * username => (string) Connect to the database as this username. 
    65      * password => (string) Password associated with the username. 
    66      * dbname   => Either the name of the local Oracle instance, or the 
    67      *             name of the entry in tnsnames.ora to which you want to connect. 
    68      * 
    69      * @param array $config An array of configuration keys. 
    70      * @throws Doctrine_Adapter_Exception 
    71      */ 
    72     public function __construct(array $config) 
     33 
     34class Doctrine_Adapter_Oracle implements Doctrine_Adapter_Interface{ 
     35        /** 
     36         *      execution mode  
     37         */ 
     38        protected $_executeMode = OCI_COMMIT_ON_SUCCESS; 
     39         
     40        /** 
     41         * Resource representing connection to database 
     42         */ 
     43        protected $_connection = false; 
     44 
     45         
     46        protected $_attributes = array( Doctrine::ATTR_DRIVER_NAME      => "oci8", 
     47                                                                        Doctrine::ATTR_ERRMODE          => Doctrine::ERRMODE_SILENT,  
     48                                                                        ); 
     49         
     50        /** 
     51         * User-provided configuration. 
     52         * 
     53         * Basic keys are: 
     54         * 
     55         * username => (string) Connect to the database as this username. 
     56         * password => (string) Password associated with the username. 
     57         * dbname   => Either the name of the local Oracle instance, or the 
     58         *             name of the entry in tnsnames.ora to which you want to connect. 
     59         * 
     60         * @var array 
     61         */ 
     62        protected $_config = array( 
     63                'dbname'       => null, 
     64                'username'     => null, 
     65                'password'     => null, 
     66            'charset'      => null, 
     67        ); 
     68 
     69    /** 
     70     * Doctrine Oracle adapter constructor 
     71     * 
     72     * <code> 
     73     * $conn = new Doctrine_Adapter_Oracle(array('dbname'=>'db','username'=>'usr','password'=>'pass')); 
     74     * </code> 
     75     * 
     76     * @param string $name  
     77     * @return void 
     78     */ 
     79    public function __construct($config = array()){ 
     80        if ( ! isset($config['password']) || ! isset($config['username'])) { 
     81                throw new Doctrine_Adapter_Exception('config array must have at least a username and a password'); 
     82        } 
     83          
     84        $this->_config['username'] = $config['username']; 
     85        $this->_config['password'] = $config['password']; 
     86        $this->_config['dbname'] = $config['dbname']; 
     87        $this->_config['charset'] = $config['charset']; 
     88    } 
     89 
     90    private function connect(){ 
     91         
     92        $this->_connection = @oci_connect($this->_config['username'], $this->_config['password'], $this->_config['dbname'], $this->_config['charset'] ); 
     93         
     94        if( $this->_connection === false){ 
     95                throw new Exception(sprintf("Unable to Connect to :'%s' as '%s'", $this->_config['dbname'], $this->_config['username'])); 
     96        } 
     97    } 
     98    /** 
     99     * Prepare a query statement 
     100     * 
     101     * @param string $query Query to prepare 
     102     * @return Doctrine_Adapter_Statement_Oracle $stmt prepared statement 
     103     */ 
     104    public function prepare($query){ 
     105        if($this->_connection ===false){ 
     106                $this->connect(); 
     107        } 
     108        $oci_stmt = $this->parseQuery($query); 
     109        $stmt = new Doctrine_Adapter_Statement_Oracle($this, $oci_stmt, $this->_executeMode); 
     110        //$stmt->queryString = $query; 
     111 
     112        return $stmt; 
     113    } 
     114 
     115    /** 
     116     * Execute query and return results as statement object 
     117     * 
     118     * @param string $query  
     119     * @return Doctrine_Adapter_Statement_Oracle $stmt 
     120     */ 
     121    public function query($query){ 
     122                if($this->_connection ===false){ 
     123                $this->connect(); 
     124        } 
     125 
     126                $resource = $this->parseQuery($query); 
     127         
     128        $stmt = new Doctrine_Adapter_Statement_Oracle($this, $resource,$this->_executeMode); 
     129        $stmt->execute(); 
     130         
     131        return $stmt; 
     132    } 
     133        private function parseQuery($query){ 
     134 
     135                $bind_index = 0; 
     136 
     137                /* 
     138                 * Replace ? bind-placeholders with :bind_var_ variables 
     139                 */ 
     140 
     141                $query = preg_replace("/(\?)/e", '":oci_b_var_". $bind_index++' , $query); 
     142                //print $query.PHP_EOL; 
     143                $resource =  @oci_parse  ( $this->_connection  , $query  ); 
     144                 
     145                if( $resource === false){ 
     146                        //TODO handle error 
     147                        print "error in parseQuery"; 
     148                } 
     149                 
     150                return $resource; 
     151        } 
     152 
     153    /** 
     154     * Quote a value for the dbms 
     155     * 
     156     * @param string $input  
     157     * @return string $quoted 
     158     */ 
     159    public function quote($input) 
    73160    { 
    74         if ( ! isset($config['password']) || ! isset($config['username'])) { 
    75             throw new Doctrine_Adapter_Exception('config array must have at least a username and a password'); 
    76         } 
    77  
    78         // keep the config 
    79         $this->_config = array_merge($this->_config, (array) $config); 
    80     } 
    81  
    82     /** 
    83      * Creates a connection resource. 
    84      * 
     161        return "'" . str_replace("'","''",$input) . "'"; 
     162    } 
     163 
     164    /** 
     165     * Execute a raw sql statement 
     166     * 
     167     * @param string $statement  
    85168     * @return void 
    86      * @throws Doctrine_Adapter_Exception 
    87      */ 
    88     protected function _connect() 
     169     */ 
     170    public function exec($statement) 
    89171    { 
    90         if (is_resource($this->_connection)) { 
    91             // connection already exists 
    92             return; 
    93         } 
    94  
    95         if ( ! extension_loaded('oci8')) { 
    96             throw new Doctrine_Adapter_Exception('The OCI8 extension is required for this adapter but not loaded'); 
    97         } 
    98  
    99         if (isset($this->_config['dbname'])) { 
    100             $this->_connection = @oci_connect( 
    101                 $this->_config['username'], 
    102                 $this->_config['password'], 
    103                 $this->_config['dbname']); 
    104         } else { 
    105             $this->_connection = oci_connect( 
    106                 $this->_config['username'], 
    107                 $this->_config['password']); 
    108         } 
    109  
    110         // check the connection 
    111         if ( ! $this->_connection) { 
    112             throw new Doctrine_Adapter_Exception(oci_error()); 
    113         } 
    114     } 
    115  
    116     /** 
    117      * Force the connection to close. 
     172        if($this->_connection ===false){ 
     173                $this->connect(); 
     174        } 
     175                $resource = $this->parseQuery($statement); 
     176         
     177        $stmt = new Doctrine_Adapter_Statement_Oracle($this, $resource, $this->_executeMode); 
     178        $stmt->execute(); 
     179        $count = $stmt->rowCount(); 
     180         
     181        return $count; 
     182    } 
     183 
     184    /** 
     185     * Get the id of the last inserted record 
     186     * 
     187     * @return integer $id 
     188     */ 
     189    public function lastInsertId(){ 
     190        throw new Exception("unsupported"); 
     191    } 
     192 
     193    /** 
     194     * Begin a transaction 
     195     * 
     196     * @return boolean 
     197     */ 
     198    public function beginTransaction() 
     199    { 
     200       $this->_executeMode = OCI_DEFAULT; 
     201       return true; 
     202    } 
     203 
     204    /** 
     205     * Commit a transaction 
    118206     * 
    119207     * @return void 
    120208     */ 
    121     public function closeConnection() 
    122     { 
    123         if (is_resource($this->_connection)) { 
    124             oci_close($this->_connection); 
    125         } 
    126         $this->_connection = null; 
    127     } 
    128  
    129     /** 
    130      * Returns an SQL statement for preparation. 
    131      * 
    132      * @param string $sql The SQL statement with placeholders. 
    133      * @return Doctrine_Statement_Oracle 
    134      */ 
    135     public function prepare($sql) 
    136     { 
    137         $this->_connect(); 
    138         $stmt = new Doctrine_Statement_Oracle($this, $sql); 
    139         $stmt->setFetchMode($this->_fetchMode); 
    140         return $stmt; 
    141     } 
    142  
    143     /** 
    144      * Quote a raw string. 
    145      * 
    146      * @param string $value     Raw string 
    147      * @return string           Quoted string 
    148      */ 
    149     protected function _quote($value) 
    150     { 
    151         $value = str_replace("'", "''", $value); 
    152         return "'" . addcslashes($value, "\000\n\r\\\032") . "'"; 
    153     } 
    154  
    155     /** 
    156      * Quote a table identifier and alias. 
    157      * 
    158      * @param string|array|Doctrine_Expr $ident The identifier or expression. 
    159      * @param string $alias An alias for the table. 
    160      * @return string The quoted identifier and alias. 
    161      */ 
    162     public function quoteTableAs($ident, $alias) 
    163     { 
    164         // Oracle doesn't allow the 'AS' keyword between the table identifier/expression and alias. 
    165         return $this->_quoteIdentifierAs($ident, $alias, ' '); 
    166     } 
    167  
    168     /** 
    169      * Leave autocommit mode and begin a transaction. 
    170      * 
    171      * @return void 
    172      */ 
    173     protected function _beginTransaction() 
    174     { 
    175         $this->_setExecuteMode(OCI_DEFAULT); 
    176     } 
    177  
    178     /** 
    179      * Commit a transaction and return to autocommit mode. 
    180      * 
    181      * @return void 
    182      * @throws Doctrine_Adapter_Exception 
    183      */ 
    184     protected function _commit() 
    185     { 
    186         if ( ! oci_commit($this->_connection)) { 
    187             throw new Doctrine_Adapter_Exception(oci_error($this->_connection)); 
    188         } 
    189         $this->_setExecuteMode(OCI_COMMIT_ON_SUCCESS); 
    190     } 
    191  
    192     /** 
    193      * Roll back a transaction and return to autocommit mode. 
    194      * 
    195      * @return void 
    196      * @throws Doctrine_Adapter_Exception 
    197      */ 
    198     protected function _rollBack() 
    199     { 
    200         if ( ! oci_rollback($this->_connection)) { 
    201             throw new Doctrine_Adapter_Exception(oci_error($this->_connection)); 
    202         } 
    203         $this->_setExecuteMode(OCI_COMMIT_ON_SUCCESS); 
    204     } 
    205  
    206     /** 
    207      * Set the fetch mode. 
    208      * 
    209      * @todo Support FETCH_CLASS and FETCH_INTO. 
    210      * 
    211      * @param integer $mode A fetch mode. 
    212      * @return void 
    213      * @throws Doctrine_Adapter_Exception 
    214      */ 
    215     public function setFetchMode($mode) 
    216     { 
    217         switch ($mode) { 
    218             case Doctrine::FETCH_NUM:   // seq array 
    219             case Doctrine::FETCH_ASSOC: // assoc array 
    220             case Doctrine::FETCH_BOTH:  // seq+assoc array 
    221             case Doctrine::FETCH_OBJ:   // object 
    222                 $this->_fetchMode = $mode; 
    223                 break; 
    224             default: 
    225                 throw new Doctrine_Adapter_Exception('Invalid fetch mode specified'); 
    226                 break; 
    227         } 
    228     } 
    229  
    230     /** 
    231      * @param integer $mode 
    232      * @throws Doctrine_Adapter_Exception 
    233      */ 
    234     private function _setExecuteMode($mode) 
    235     { 
    236         switch($mode) { 
    237             case OCI_COMMIT_ON_SUCCESS: 
    238             case OCI_DEFAULT: 
    239             case OCI_DESCRIBE_ONLY: 
    240                 $this->_executeMode = $mode; 
    241                 break; 
    242             default: 
    243                 throw new Doctrine_Adapter_Exception('wrong execution mode specified'); 
    244                 break; 
    245         } 
    246     } 
    247  
    248     /** 
    249      * Get the current execute mode 
    250      * 
    251      * @return integer $mode 
    252      */ 
    253     public function _getExecuteMode() 
    254     { 
    255         return $this->_executeMode; 
    256     } 
     209    public function commit(){ 
     210        if($this->_connection ===false){ 
     211                $this->connect(); 
     212        } 
     213        return @oci_commit($this->_connection); 
     214    } 
     215 
     216    /** 
     217     * Rollback a transaction 
     218     * 
     219     * @return boolean 
     220     */ 
     221    public function rollBack(){ 
     222        if($this->_connection ===false){ 
     223                $this->connect(); 
     224        } 
     225       return @oci_rollback($this->_connection); 
     226    } 
     227 
     228        /** 
     229     * Set connection attribute 
     230     * 
     231     * @param integer $attribute 
     232     * @param mixed $value                  the value of given attribute 
     233     * @return boolean                      Returns TRUE on success or FALSE on failure. 
     234     */ 
     235    public function setAttribute($attribute, $value){ 
     236        switch($attribute){ 
     237                case Doctrine::ATTR_DRIVER_NAME: 
     238                        //TODO throw an error since driver name can not be changed 
     239                case Doctrine::ATTR_ERRMODE: 
     240                        break; 
     241                case Doctrine::ATTR_CASE: 
     242                        if($value == Doctrine::CASE_NATURAL){ 
     243                                break; 
     244                        }else{ 
     245                                throw new Doctrine_Adapter_Exception("Unsupported Option for ATTR_CASE: $value"); 
     246                        } 
     247                default: 
     248                        throw new Doctrine_Adapter_Exception("Unsupported Attribute: $attribute"); 
     249                        return false; 
     250        } 
     251        $this->_attributes[$attribute] = $value; 
     252        return true; 
     253    } 
     254         
     255        /** 
     256     * Retrieve a statement attribute  
     257     * 
     258     * @param integer $attribute 
     259     * @see Doctrine::ATTR_* constants 
     260     * @return mixed                        the attribute value 
     261     */ 
     262    public function getAttribute($attribute){ 
     263        return $this->_attributes[$attribute]; 
     264    } 
     265     
     266    public function errorCode(){ 
     267        if( is_resource($this->_connection)){ 
     268                        $error = @oci_error($this->_connection);                 
     269        }else{ 
     270                $error = @oci_error(); 
     271        } 
     272        return $error['code']; 
     273    } 
     274 
     275    public function errorInfo(){ 
     276        if( is_resource($this->_connection)){ 
     277                        $error = @oci_error($this->_connection);                 
     278        }else{ 
     279                $error = @oci_error(); 
     280        } 
     281        return $error['message']; 
     282    } 
     283     
    257284}