File indexing completed on 2025-01-19 05:21:02
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Db 0017 * @subpackage Statement 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_Db_Statement 0025 */ 0026 // require_once 'Zend/Db/Statement.php'; 0027 0028 /** 0029 * Extends for Microsoft SQL Server Driver for PHP 0030 * 0031 * @category Zend 0032 * @package Zend_Db 0033 * @subpackage Statement 0034 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0035 * @license http://framework.zend.com/license/new-bsd New BSD License 0036 */ 0037 class Zend_Db_Statement_Sqlsrv extends Zend_Db_Statement 0038 { 0039 0040 /** 0041 * The connection_stmt object original string. 0042 */ 0043 protected $_originalSQL; 0044 0045 /** 0046 * Column names. 0047 */ 0048 protected $_keys; 0049 0050 /** 0051 * Query executed 0052 */ 0053 protected $_executed = false; 0054 0055 /** 0056 * Prepares statement handle 0057 * 0058 * @param string $sql 0059 * @return void 0060 * @throws Zend_Db_Statement_Sqlsrv_Exception 0061 */ 0062 protected function _prepare($sql) 0063 { 0064 $connection = $this->_adapter->getConnection(); 0065 0066 $this->_stmt = sqlsrv_prepare($connection, $sql); 0067 0068 if (!$this->_stmt) { 0069 // require_once 'Zend/Db/Statement/Sqlsrv/Exception.php'; 0070 throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); 0071 } 0072 0073 $this->_originalSQL = $sql; 0074 } 0075 0076 /** 0077 * Binds a parameter to the specified variable name. 0078 * 0079 * @param mixed $parameter Name the parameter, either integer or string. 0080 * @param mixed $variable Reference to PHP variable containing the value. 0081 * @param mixed $type OPTIONAL Datatype of SQL parameter. 0082 * @param mixed $length OPTIONAL Length of SQL parameter. 0083 * @param mixed $options OPTIONAL Other options. 0084 * @return bool 0085 * @throws Zend_Db_Statement_Exception 0086 */ 0087 protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) 0088 { 0089 //Sql server doesn't support bind by name 0090 return true; 0091 } 0092 0093 /** 0094 * Closes the cursor, allowing the statement to be executed again. 0095 * 0096 * @return bool 0097 */ 0098 public function closeCursor() 0099 { 0100 if (!$this->_stmt) { 0101 return false; 0102 } 0103 0104 sqlsrv_free_stmt($this->_stmt); 0105 $this->_stmt = false; 0106 return true; 0107 } 0108 0109 /** 0110 * Returns the number of columns in the result set. 0111 * Returns null if the statement has no result set metadata. 0112 * 0113 * @return int The number of columns. 0114 */ 0115 public function columnCount() 0116 { 0117 if ($this->_stmt && $this->_executed) { 0118 return sqlsrv_num_fields($this->_stmt); 0119 } 0120 0121 return 0; 0122 } 0123 0124 0125 /** 0126 * Retrieves the error code, if any, associated with the last operation on 0127 * the statement handle. 0128 * 0129 * @return string error code. 0130 */ 0131 public function errorCode() 0132 { 0133 if (!$this->_stmt) { 0134 return false; 0135 } 0136 0137 $error = sqlsrv_errors(); 0138 if (!$error) { 0139 return false; 0140 } 0141 0142 return $error[0]['code']; 0143 } 0144 0145 0146 /** 0147 * Retrieves an array of error information, if any, associated with the 0148 * last operation on the statement handle. 0149 * 0150 * @return array 0151 */ 0152 public function errorInfo() 0153 { 0154 if (!$this->_stmt) { 0155 return false; 0156 } 0157 0158 $error = sqlsrv_errors(); 0159 if (!$error) { 0160 return false; 0161 } 0162 0163 return array( 0164 $error[0]['code'], 0165 $error[0]['message'], 0166 ); 0167 } 0168 0169 0170 /** 0171 * Executes a prepared statement. 0172 * 0173 * @param array $params OPTIONAL Values to bind to parameter placeholders. 0174 * @return bool 0175 * @throws Zend_Db_Statement_Exception 0176 */ 0177 public function _execute(array $params = null) 0178 { 0179 $connection = $this->_adapter->getConnection(); 0180 if (!$this->_stmt) { 0181 return false; 0182 } 0183 0184 if ($params !== null) { 0185 if (!is_array($params)) { 0186 $params = array($params); 0187 } 0188 $error = false; 0189 0190 // make all params passed by reference 0191 $params_ = array(); 0192 $temp = array(); 0193 $i = 1; 0194 foreach ($params as $param) { 0195 $temp[$i] = $param; 0196 $params_[] = &$temp[$i]; 0197 $i++; 0198 } 0199 $params = $params_; 0200 } 0201 0202 $this->_stmt = sqlsrv_query($connection, $this->_originalSQL, $params); 0203 0204 if (!$this->_stmt) { 0205 // require_once 'Zend/Db/Statement/Sqlsrv/Exception.php'; 0206 throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); 0207 } 0208 0209 $this->_executed = true; 0210 0211 return (!$this->_stmt); 0212 } 0213 0214 /** 0215 * Fetches a row from the result set. 0216 * 0217 * @param int $style OPTIONAL Fetch mode for this fetch operation. 0218 * @param int $cursor OPTIONAL Absolute, relative, or other. 0219 * @param int $offset OPTIONAL Number for absolute or relative cursors. 0220 * @return mixed Array, object, or scalar depending on fetch mode. 0221 * @throws Zend_Db_Statement_Exception 0222 */ 0223 public function fetch($style = null, $cursor = null, $offset = null) 0224 { 0225 if (!$this->_stmt) { 0226 return false; 0227 } 0228 0229 if (null === $style) { 0230 $style = $this->_fetchMode; 0231 } 0232 0233 $values = sqlsrv_fetch_array($this->_stmt, SQLSRV_FETCH_ASSOC); 0234 0235 if (!$values && (null !== $error = sqlsrv_errors())) { 0236 // require_once 'Zend/Db/Statement/Sqlsrv/Exception.php'; 0237 throw new Zend_Db_Statement_Sqlsrv_Exception($error); 0238 } 0239 0240 if (null === $values) { 0241 return null; 0242 } 0243 0244 if (!$this->_keys) { 0245 foreach ($values as $key => $value) { 0246 $this->_keys[] = $this->_adapter->foldCase($key); 0247 } 0248 } 0249 0250 $values = array_values($values); 0251 0252 $row = false; 0253 switch ($style) { 0254 case Zend_Db::FETCH_NUM: 0255 $row = $values; 0256 break; 0257 case Zend_Db::FETCH_ASSOC: 0258 $row = array_combine($this->_keys, $values); 0259 break; 0260 case Zend_Db::FETCH_BOTH: 0261 $assoc = array_combine($this->_keys, $values); 0262 $row = array_merge($values, $assoc); 0263 break; 0264 case Zend_Db::FETCH_OBJ: 0265 $row = (object) array_combine($this->_keys, $values); 0266 break; 0267 case Zend_Db::FETCH_BOUND: 0268 $assoc = array_combine($this->_keys, $values); 0269 $row = array_merge($values, $assoc); 0270 $row = $this->_fetchBound($row); 0271 break; 0272 default: 0273 // require_once 'Zend/Db/Statement/Sqlsrv/Exception.php'; 0274 throw new Zend_Db_Statement_Sqlsrv_Exception("Invalid fetch mode '$style' specified"); 0275 break; 0276 } 0277 0278 return $row; 0279 } 0280 0281 /** 0282 * Returns a single column from the next row of a result set. 0283 * 0284 * @param int $col OPTIONAL Position of the column to fetch. 0285 * @return string 0286 * @throws Zend_Db_Statement_Exception 0287 */ 0288 public function fetchColumn($col = 0) 0289 { 0290 if (!$this->_stmt) { 0291 return false; 0292 } 0293 0294 if (!sqlsrv_fetch($this->_stmt)) { 0295 if (null !== $error = sqlsrv_errors()) { 0296 // require_once 'Zend/Db/Statement/Sqlsrv/Exception.php'; 0297 throw new Zend_Db_Statement_Sqlsrv_Exception($error); 0298 } 0299 0300 // If no error, there is simply no record 0301 return false; 0302 } 0303 0304 $data = sqlsrv_get_field($this->_stmt, $col); //0-based 0305 if ($data === false) { 0306 // require_once 'Zend/Db/Statement/Sqlsrv/Exception.php'; 0307 throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); 0308 } 0309 0310 return $data; 0311 } 0312 0313 /** 0314 * Fetches the next row and returns it as an object. 0315 * 0316 * @param string $class OPTIONAL Name of the class to create. 0317 * @param array $config OPTIONAL Constructor arguments for the class. 0318 * @return mixed One object instance of the specified class. 0319 * @throws Zend_Db_Statement_Exception 0320 */ 0321 public function fetchObject($class = 'stdClass', array $config = array()) 0322 { 0323 if (!$this->_stmt) { 0324 return false; 0325 } 0326 0327 $obj = sqlsrv_fetch_object($this->_stmt); 0328 0329 if ($error = sqlsrv_errors()) { 0330 // require_once 'Zend/Db/Statement/Sqlsrv/Exception.php'; 0331 throw new Zend_Db_Statement_Sqlsrv_Exception($error); 0332 } 0333 0334 /* @todo XXX handle parameters */ 0335 0336 if (null === $obj) { 0337 return false; 0338 } 0339 0340 return $obj; 0341 } 0342 0343 /** 0344 * Returns metadata for a column in a result set. 0345 * 0346 * @param int $column 0347 * @return mixed 0348 * @throws Zend_Db_Statement_Sqlsrv_Exception 0349 */ 0350 public function getColumnMeta($column) 0351 { 0352 $fields = sqlsrv_field_metadata($this->_stmt); 0353 0354 if (!$fields) { 0355 throw new Zend_Db_Statement_Sqlsrv_Exception('Column metadata can not be fetched'); 0356 } 0357 0358 if (!isset($fields[$column])) { 0359 throw new Zend_Db_Statement_Sqlsrv_Exception('Column index does not exist in statement'); 0360 } 0361 0362 return $fields[$column]; 0363 } 0364 0365 /** 0366 * Retrieves the next rowset (result set) for a SQL statement that has 0367 * multiple result sets. An example is a stored procedure that returns 0368 * the results of multiple queries. 0369 * 0370 * @return bool 0371 * @throws Zend_Db_Statement_Exception 0372 */ 0373 public function nextRowset() 0374 { 0375 if (sqlsrv_next_result($this->_stmt) === false) { 0376 // require_once 'Zend/Db/Statement/Sqlsrv/Exception.php'; 0377 throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); 0378 } 0379 0380 // reset column keys 0381 $this->_keys = null; 0382 0383 return true; 0384 } 0385 0386 /** 0387 * Returns the number of rows affected by the execution of the 0388 * last INSERT, DELETE, or UPDATE statement executed by this 0389 * statement object. 0390 * 0391 * @return int The number of rows affected. 0392 * @throws Zend_Db_Statement_Exception 0393 */ 0394 public function rowCount() 0395 { 0396 if (!$this->_stmt) { 0397 return false; 0398 } 0399 0400 if (!$this->_executed) { 0401 return 0; 0402 } 0403 0404 $num_rows = sqlsrv_rows_affected($this->_stmt); 0405 0406 // Strict check is necessary; 0 is a valid return value 0407 if ($num_rows === false) { 0408 // require_once 'Zend/Db/Statement/Sqlsrv/Exception.php'; 0409 throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); 0410 } 0411 0412 return $num_rows; 0413 } 0414 0415 /** 0416 * Returns an array containing all of the result set rows. 0417 * 0418 * @param int $style OPTIONAL Fetch mode. 0419 * @param int $col OPTIONAL Column number, if fetch mode is by column. 0420 * @return array Collection of rows, each in a format by the fetch mode. 0421 * 0422 * Behaves like parent, but if limit() 0423 * is used, the final result removes the extra column 0424 * 'zend_db_rownum' 0425 */ 0426 public function fetchAll($style = null, $col = null) 0427 { 0428 $data = parent::fetchAll($style, $col); 0429 $results = array(); 0430 $remove = $this->_adapter->foldCase('ZEND_DB_ROWNUM'); 0431 0432 foreach ($data as $row) { 0433 if (is_array($row) && array_key_exists($remove, $row)) { 0434 unset($row[$remove]); 0435 } 0436 $results[] = $row; 0437 } 0438 return $results; 0439 } 0440 }