1<?php 2/** 3 * Zend Framework (http://framework.zend.com/) 4 * 5 * @link http://github.com/zendframework/zf2 for the canonical source repository 6 * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com) 7 * @license http://framework.zend.com/license/new-bsd New BSD License 8 */ 9 10namespace Zend\Db\Adapter\Driver\IbmDb2; 11 12use Zend\Db\Adapter\Driver\AbstractConnection; 13use Zend\Db\Adapter\Exception; 14 15class Connection extends AbstractConnection 16{ 17 /** 18 * @var IbmDb2 19 */ 20 protected $driver = null; 21 22 /** 23 * i5 OS 24 * 25 * @var bool 26 */ 27 protected $i5; 28 29 /** 30 * Previous autocommit set 31 * 32 * @var mixed 33 */ 34 protected $prevAutocommit; 35 36 /** 37 * Constructor 38 * 39 * @param array|resource|null $connectionParameters (ibm_db2 connection resource) 40 * @throws Exception\InvalidArgumentException 41 */ 42 public function __construct($connectionParameters = null) 43 { 44 if (is_array($connectionParameters)) { 45 $this->setConnectionParameters($connectionParameters); 46 } elseif (is_resource($connectionParameters)) { 47 $this->setResource($connectionParameters); 48 } elseif (null !== $connectionParameters) { 49 throw new Exception\InvalidArgumentException( 50 '$connection must be an array of parameters, a db2 connection resource or null' 51 ); 52 } 53 } 54 55 /** 56 * Set driver 57 * 58 * @param IbmDb2 $driver 59 * @return self Provides a fluent interface 60 */ 61 public function setDriver(IbmDb2 $driver) 62 { 63 $this->driver = $driver; 64 65 return $this; 66 } 67 68 /** 69 * @param resource $resource DB2 resource 70 * @return self Provides a fluent interface 71 */ 72 public function setResource($resource) 73 { 74 if (! is_resource($resource) || get_resource_type($resource) !== 'DB2 Connection') { 75 throw new Exception\InvalidArgumentException('The resource provided must be of type "DB2 Connection"'); 76 } 77 $this->resource = $resource; 78 79 return $this; 80 } 81 82 /** 83 * {@inheritDoc} 84 */ 85 public function getCurrentSchema() 86 { 87 if (! $this->isConnected()) { 88 $this->connect(); 89 } 90 91 $info = db2_server_info($this->resource); 92 93 return (isset($info->DB_NAME) ? $info->DB_NAME : ''); 94 } 95 96 /** 97 * {@inheritDoc} 98 */ 99 public function connect() 100 { 101 if (is_resource($this->resource)) { 102 return $this; 103 } 104 105 // localize 106 $p = $this->connectionParameters; 107 108 // given a list of key names, test for existence in $p 109 $findParameterValue = function (array $names) use ($p) { 110 foreach ($names as $name) { 111 if (isset($p[$name])) { 112 return $p[$name]; 113 } 114 } 115 116 return; 117 }; 118 119 $database = $findParameterValue(['database', 'db']); 120 $username = $findParameterValue(['username', 'uid', 'UID']); 121 $password = $findParameterValue(['password', 'pwd', 'PWD']); 122 $isPersistent = $findParameterValue(['persistent', 'PERSISTENT', 'Persistent']); 123 $options = (isset($p['driver_options']) ? $p['driver_options'] : []); 124 $connect = ((bool) $isPersistent) ? 'db2_pconnect' : 'db2_connect'; 125 126 $this->resource = $connect($database, $username, $password, $options); 127 128 if ($this->resource === false) { 129 throw new Exception\RuntimeException(sprintf( 130 '%s: Unable to connect to database', 131 __METHOD__ 132 )); 133 } 134 135 return $this; 136 } 137 138 /** 139 * {@inheritDoc} 140 */ 141 public function isConnected() 142 { 143 return ($this->resource !== null); 144 } 145 146 /** 147 * {@inheritDoc} 148 */ 149 public function disconnect() 150 { 151 if ($this->resource) { 152 db2_close($this->resource); 153 $this->resource = null; 154 } 155 156 return $this; 157 } 158 159 /** 160 * {@inheritDoc} 161 */ 162 public function beginTransaction() 163 { 164 if ($this->isI5() && ! ini_get('ibm_db2.i5_allow_commit')) { 165 throw new Exception\RuntimeException( 166 'DB2 transactions are not enabled, you need to set the ibm_db2.i5_allow_commit=1 in your php.ini' 167 ); 168 } 169 170 if (! $this->isConnected()) { 171 $this->connect(); 172 } 173 174 $this->prevAutocommit = db2_autocommit($this->resource); 175 db2_autocommit($this->resource, DB2_AUTOCOMMIT_OFF); 176 $this->inTransaction = true; 177 178 return $this; 179 } 180 181 /** 182 * {@inheritDoc} 183 */ 184 public function commit() 185 { 186 if (! $this->isConnected()) { 187 $this->connect(); 188 } 189 190 if (! db2_commit($this->resource)) { 191 throw new Exception\RuntimeException("The commit has not been successful"); 192 } 193 194 if ($this->prevAutocommit) { 195 db2_autocommit($this->resource, $this->prevAutocommit); 196 } 197 198 $this->inTransaction = false; 199 200 return $this; 201 } 202 203 /** 204 * Rollback 205 * 206 * @return self Provides a fluent interface 207 * @throws Exception\RuntimeException 208 */ 209 public function rollback() 210 { 211 if (! $this->isConnected()) { 212 throw new Exception\RuntimeException('Must be connected before you can rollback.'); 213 } 214 215 if (! $this->inTransaction()) { 216 throw new Exception\RuntimeException('Must call beginTransaction() before you can rollback.'); 217 } 218 219 if (! db2_rollback($this->resource)) { 220 throw new Exception\RuntimeException('The rollback has not been successful'); 221 } 222 223 if ($this->prevAutocommit) { 224 db2_autocommit($this->resource, $this->prevAutocommit); 225 } 226 227 $this->inTransaction = false; 228 229 return $this; 230 } 231 232 /** 233 * {@inheritDoc} 234 */ 235 public function execute($sql) 236 { 237 if (! $this->isConnected()) { 238 $this->connect(); 239 } 240 241 if ($this->profiler) { 242 $this->profiler->profilerStart($sql); 243 } 244 245 set_error_handler(function () { 246 }, E_WARNING); // suppress warnings 247 $resultResource = db2_exec($this->resource, $sql); 248 restore_error_handler(); 249 250 if ($this->profiler) { 251 $this->profiler->profilerFinish($sql); 252 } 253 254 // if the returnValue is something other than a pg result resource, bypass wrapping it 255 if ($resultResource === false) { 256 throw new Exception\InvalidQueryException(db2_stmt_errormsg()); 257 } 258 259 return $this->driver->createResult(($resultResource === true) ? $this->resource : $resultResource); 260 } 261 262 /** 263 * {@inheritDoc} 264 */ 265 public function getLastGeneratedValue($name = null) 266 { 267 return db2_last_insert_id($this->resource); 268 } 269 270 /** 271 * Determine if the OS is OS400 (AS400, IBM i) 272 * 273 * @return bool 274 */ 275 protected function isI5() 276 { 277 if (isset($this->i5)) { 278 return $this->i5; 279 } 280 281 $this->i5 = (php_uname('s') == 'OS400'); 282 283 return $this->i5; 284 } 285} 286