1<?php 2/** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to license@zend.com so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Db 17 * @subpackage Statement 18 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 19 * @license http://framework.zend.com/license/new-bsd New BSD License 20 * @version $Id$ 21 */ 22 23/** 24 * @see Zend_Db_Statement 25 */ 26 27/** 28 * Extends for DB2 native adapter. 29 * 30 * @package Zend_Db 31 * @subpackage Statement 32 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 33 * @license http://framework.zend.com/license/new-bsd New BSD License 34 */ 35class Zend_Db_Statement_Db2 extends Zend_Db_Statement 36{ 37 38 /** 39 * Column names. 40 */ 41 protected $_keys; 42 43 /** 44 * Fetched result values. 45 */ 46 protected $_values; 47 48 /** 49 * Prepare a statement handle. 50 * 51 * @param string $sql 52 * @return void 53 * @throws Zend_Db_Statement_Db2_Exception 54 */ 55 public function _prepare($sql) 56 { 57 $connection = $this->_adapter->getConnection(); 58 59 // db2_prepare on i5 emits errors, these need to be 60 // suppressed so that proper exceptions can be thrown 61 $this->_stmt = @db2_prepare($connection, $sql); 62 63 if (!$this->_stmt) { 64 /** 65 * @see Zend_Db_Statement_Db2_Exception 66 */ 67 throw new Zend_Db_Statement_Db2_Exception( 68 db2_stmt_errormsg(), 69 db2_stmt_error() 70 ); 71 } 72 } 73 74 /** 75 * Binds a parameter to the specified variable name. 76 * 77 * @param mixed $parameter Name the parameter, either integer or string. 78 * @param mixed $variable Reference to PHP variable containing the value. 79 * @param mixed $type OPTIONAL Datatype of SQL parameter. 80 * @param mixed $length OPTIONAL Length of SQL parameter. 81 * @param mixed $options OPTIONAL Other options. 82 * @return bool 83 * @throws Zend_Db_Statement_Db2_Exception 84 */ 85 public function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) 86 { 87 if ($type === null) { 88 $type = DB2_PARAM_IN; 89 } 90 91 if (isset($options['data-type'])) { 92 $datatype = $options['data-type']; 93 } else { 94 $datatype = DB2_CHAR; 95 } 96 97 if (!db2_bind_param($this->_stmt, $parameter, "variable", $type, $datatype)) { 98 /** 99 * @see Zend_Db_Statement_Db2_Exception 100 */ 101 throw new Zend_Db_Statement_Db2_Exception( 102 db2_stmt_errormsg(), 103 db2_stmt_error() 104 ); 105 } 106 107 return true; 108 } 109 110 /** 111 * Closes the cursor, allowing the statement to be executed again. 112 * 113 * @return bool 114 */ 115 public function closeCursor() 116 { 117 if (!$this->_stmt) { 118 return false; 119 } 120 db2_free_stmt($this->_stmt); 121 $this->_stmt = false; 122 return true; 123 } 124 125 126 /** 127 * Returns the number of columns in the result set. 128 * Returns null if the statement has no result set metadata. 129 * 130 * @return int The number of columns. 131 */ 132 public function columnCount() 133 { 134 if (!$this->_stmt) { 135 return false; 136 } 137 return db2_num_fields($this->_stmt); 138 } 139 140 /** 141 * Retrieves the error code, if any, associated with the last operation on 142 * the statement handle. 143 * 144 * @return string error code. 145 */ 146 public function errorCode() 147 { 148 if (!$this->_stmt) { 149 return false; 150 } 151 152 $error = db2_stmt_error(); 153 if ($error === '') { 154 return false; 155 } 156 157 return $error; 158 } 159 160 /** 161 * Retrieves an array of error information, if any, associated with the 162 * last operation on the statement handle. 163 * 164 * @return array 165 */ 166 public function errorInfo() 167 { 168 $error = $this->errorCode(); 169 if ($error === false){ 170 return false; 171 } 172 173 /* 174 * Return three-valued array like PDO. But DB2 does not distinguish 175 * between SQLCODE and native RDBMS error code, so repeat the SQLCODE. 176 */ 177 return array( 178 $error, 179 $error, 180 db2_stmt_errormsg() 181 ); 182 } 183 184 /** 185 * Executes a prepared statement. 186 * 187 * @param array $params OPTIONAL Values to bind to parameter placeholders. 188 * @return bool 189 * @throws Zend_Db_Statement_Db2_Exception 190 */ 191 public function _execute(array $params = null) 192 { 193 if (!$this->_stmt) { 194 return false; 195 } 196 197 $retval = true; 198 if ($params !== null) { 199 $retval = @db2_execute($this->_stmt, $params); 200 } else { 201 $retval = @db2_execute($this->_stmt); 202 } 203 204 if ($retval === false) { 205 /** 206 * @see Zend_Db_Statement_Db2_Exception 207 */ 208 throw new Zend_Db_Statement_Db2_Exception( 209 db2_stmt_errormsg(), 210 db2_stmt_error()); 211 } 212 213 $this->_keys = array(); 214 if ($field_num = $this->columnCount()) { 215 for ($i = 0; $i < $field_num; $i++) { 216 $name = db2_field_name($this->_stmt, $i); 217 $this->_keys[] = $name; 218 } 219 } 220 221 $this->_values = array(); 222 if ($this->_keys) { 223 $this->_values = array_fill(0, count($this->_keys), null); 224 } 225 226 return $retval; 227 } 228 229 /** 230 * Fetches a row from the result set. 231 * 232 * @param int $style OPTIONAL Fetch mode for this fetch operation. 233 * @param int $cursor OPTIONAL Absolute, relative, or other. 234 * @param int $offset OPTIONAL Number for absolute or relative cursors. 235 * @return mixed Array, object, or scalar depending on fetch mode. 236 * @throws Zend_Db_Statement_Db2_Exception 237 */ 238 public function fetch($style = null, $cursor = null, $offset = null) 239 { 240 if (!$this->_stmt) { 241 return false; 242 } 243 244 if ($style === null) { 245 $style = $this->_fetchMode; 246 } 247 248 switch ($style) { 249 case Zend_Db::FETCH_NUM : 250 $row = db2_fetch_array($this->_stmt); 251 break; 252 case Zend_Db::FETCH_ASSOC : 253 $row = db2_fetch_assoc($this->_stmt); 254 break; 255 case Zend_Db::FETCH_BOTH : 256 $row = db2_fetch_both($this->_stmt); 257 break; 258 case Zend_Db::FETCH_OBJ : 259 $row = db2_fetch_object($this->_stmt); 260 break; 261 case Zend_Db::FETCH_BOUND: 262 $row = db2_fetch_both($this->_stmt); 263 if ($row !== false) { 264 return $this->_fetchBound($row); 265 } 266 break; 267 default: 268 /** 269 * @see Zend_Db_Statement_Db2_Exception 270 */ 271 throw new Zend_Db_Statement_Db2_Exception("Invalid fetch mode '$style' specified"); 272 break; 273 } 274 275 return $row; 276 } 277 278 /** 279 * Fetches the next row and returns it as an object. 280 * 281 * @param string $class OPTIONAL Name of the class to create. 282 * @param array $config OPTIONAL Constructor arguments for the class. 283 * @return mixed One object instance of the specified class. 284 */ 285 public function fetchObject($class = 'stdClass', array $config = array()) 286 { 287 $obj = $this->fetch(Zend_Db::FETCH_OBJ); 288 return $obj; 289 } 290 291 /** 292 * Retrieves the next rowset (result set) for a SQL statement that has 293 * multiple result sets. An example is a stored procedure that returns 294 * the results of multiple queries. 295 * 296 * @return bool 297 * @throws Zend_Db_Statement_Db2_Exception 298 */ 299 public function nextRowset() 300 { 301 /** 302 * @see Zend_Db_Statement_Db2_Exception 303 */ 304 throw new Zend_Db_Statement_Db2_Exception(__FUNCTION__ . '() is not implemented'); 305 } 306 307 /** 308 * Returns the number of rows affected by the execution of the 309 * last INSERT, DELETE, or UPDATE statement executed by this 310 * statement object. 311 * 312 * @return int The number of rows affected. 313 */ 314 public function rowCount() 315 { 316 if (!$this->_stmt) { 317 return false; 318 } 319 320 $num = @db2_num_rows($this->_stmt); 321 322 if ($num === false) { 323 return 0; 324 } 325 326 return $num; 327 } 328 329 /** 330 * Returns an array containing all of the result set rows. 331 * 332 * @param int $style OPTIONAL Fetch mode. 333 * @param int $col OPTIONAL Column number, if fetch mode is by column. 334 * @return array Collection of rows, each in a format by the fetch mode. 335 * 336 * Behaves like parent, but if limit() 337 * is used, the final result removes the extra column 338 * 'zend_db_rownum' 339 */ 340 public function fetchAll($style = null, $col = null) 341 { 342 $data = parent::fetchAll($style, $col); 343 $results = array(); 344 $remove = $this->_adapter->foldCase('ZEND_DB_ROWNUM'); 345 346 foreach ($data as $row) { 347 if (is_array($row) && array_key_exists($remove, $row)) { 348 unset($row[$remove]); 349 } 350 $results[] = $row; 351 } 352 return $results; 353 } 354} 355