| 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 | |
| | 34 | class 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) |
| 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 |
| 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 | |