Sqlsrv.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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-2009 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /**
  22. * @see Zend_Db_Statement
  23. */
  24. require_once 'Zend/Db/Statement.php';
  25. /**
  26. * Extends for Microsoft SQL Server Driver for PHP
  27. *
  28. * @category Zend
  29. * @package Zend_Db
  30. * @subpackage Statement
  31. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  32. * @license http://framework.zend.com/license/new-bsd New BSD License
  33. */
  34. class Zend_Db_Statement_Sqlsrv extends Zend_Db_Statement
  35. {
  36. /**
  37. * The connection_stmt object.
  38. */
  39. protected $_stmt;
  40. /**
  41. * The connection_stmt object original string.
  42. */
  43. protected $_originalSQL;
  44. /**
  45. * Column names.
  46. */
  47. protected $_keys;
  48. /**
  49. * Query executed
  50. */
  51. protected $_executed = false;
  52. /**
  53. * Prepares statement handle
  54. *
  55. * @param string $sql
  56. * @return void
  57. * @throws Zend_Db_Statement_Sqlsrv_Exception
  58. */
  59. protected function _prepare($sql)
  60. {
  61. $connection = $this->_adapter->getConnection();
  62. $this->_stmt = sqlsrv_prepare($connection, $sql);
  63. if (!$this->_stmt) {
  64. require_once 'Zend/Db/Statement/Sqlsrv/Exception.php';
  65. throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors());
  66. }
  67. $this->_originalSQL = $sql;
  68. }
  69. /**
  70. * Binds a parameter to the specified variable name.
  71. *
  72. * @param mixed $parameter Name the parameter, either integer or string.
  73. * @param mixed $variable Reference to PHP variable containing the value.
  74. * @param mixed $type OPTIONAL Datatype of SQL parameter.
  75. * @param mixed $length OPTIONAL Length of SQL parameter.
  76. * @param mixed $options OPTIONAL Other options.
  77. * @return bool
  78. * @throws Zend_Db_Statement_Exception
  79. */
  80. protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null)
  81. {
  82. //Sql server doesn't support bind by name
  83. return true;
  84. }
  85. /**
  86. * Closes the cursor, allowing the statement to be executed again.
  87. *
  88. * @return bool
  89. */
  90. public function closeCursor()
  91. {
  92. if (!$this->_stmt) {
  93. return false;
  94. }
  95. sqlsrv_free_stmt($this->_stmt);
  96. $this->_stmt = false;
  97. return true;
  98. }
  99. /**
  100. * Returns the number of columns in the result set.
  101. * Returns null if the statement has no result set metadata.
  102. *
  103. * @return int The number of columns.
  104. */
  105. public function columnCount()
  106. {
  107. if ($this->_stmt && $this->_executed) {
  108. return sqlsrv_num_fields($this->_stmt);
  109. }
  110. return 0;
  111. }
  112. /**
  113. * Retrieves the error code, if any, associated with the last operation on
  114. * the statement handle.
  115. *
  116. * @return string error code.
  117. */
  118. public function errorCode()
  119. {
  120. if (!$this->_stmt) {
  121. return false;
  122. }
  123. $error = sqlsrv_errors();
  124. if (!$error) {
  125. return false;
  126. }
  127. return $error[0]['code'];
  128. }
  129. /**
  130. * Retrieves an array of error information, if any, associated with the
  131. * last operation on the statement handle.
  132. *
  133. * @return array
  134. */
  135. public function errorInfo()
  136. {
  137. if (!$this->_stmt) {
  138. return false;
  139. }
  140. $error = sqlsrv_errors();
  141. if (!$error) {
  142. return false;
  143. }
  144. return array(
  145. $error[0]['code'],
  146. $error[0]['message'],
  147. );
  148. }
  149. /**
  150. * Executes a prepared statement.
  151. *
  152. * @param array $params OPTIONAL Values to bind to parameter placeholders.
  153. * @return bool
  154. * @throws Zend_Db_Statement_Exception
  155. */
  156. public function _execute(array $params = null)
  157. {
  158. $connection = $this->_adapter->getConnection();
  159. if (!$this->_stmt) {
  160. return false;
  161. }
  162. if ($params !== null) {
  163. if (!is_array($params)) {
  164. $params = array($params);
  165. }
  166. $error = false;
  167. // make all params passed by reference
  168. $params_ = array();
  169. $temp = array();
  170. $i = 1;
  171. foreach ($params as $param) {
  172. $temp[$i] = $param;
  173. $params_[] = &$temp[$i];
  174. $i++;
  175. }
  176. $params = $params_;
  177. }
  178. $this->_stmt = sqlsrv_query($connection, $this->_originalSQL, $params);
  179. if (!$this->_stmt) {
  180. require_once 'Zend/Db/Statement/Sqlsrv/Exception.php';
  181. throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors());
  182. }
  183. $this->_executed = true;
  184. return (!$this->_stmt);
  185. }
  186. /**
  187. * Fetches a row from the result set.
  188. *
  189. * @param int $style OPTIONAL Fetch mode for this fetch operation.
  190. * @param int $cursor OPTIONAL Absolute, relative, or other.
  191. * @param int $offset OPTIONAL Number for absolute or relative cursors.
  192. * @return mixed Array, object, or scalar depending on fetch mode.
  193. * @throws Zend_Db_Statement_Exception
  194. */
  195. public function fetch($style = null, $cursor = null, $offset = null)
  196. {
  197. if (!$this->_stmt) {
  198. return false;
  199. }
  200. if (null === $style) {
  201. $style = $this->_fetchMode;
  202. }
  203. $values = sqlsrv_fetch_array($this->_stmt, SQLSRV_FETCH_ASSOC);
  204. if (!$values && (null !== $error = sqlsrv_errors())) {
  205. require_once 'Zend/Db/Statement/Sqlsrv/Exception.php';
  206. throw new Zend_Db_Statement_Sqlsrv_Exception($error);
  207. }
  208. if (null === $values) {
  209. return null;
  210. }
  211. if (!$this->_keys) {
  212. foreach ($values as $key => $value) {
  213. $this->_keys[] = $this->_adapter->foldCase($key);
  214. }
  215. }
  216. $values = array_values($values);
  217. $row = false;
  218. switch ($style) {
  219. case Zend_Db::FETCH_NUM:
  220. $row = $values;
  221. break;
  222. case Zend_Db::FETCH_ASSOC:
  223. $row = array_combine($this->_keys, $values);
  224. break;
  225. case Zend_Db::FETCH_BOTH:
  226. $assoc = array_combine($this->_keys, $values);
  227. $row = array_merge($values, $assoc);
  228. break;
  229. case Zend_Db::FETCH_OBJ:
  230. $row = (object) array_combine($this->_keys, $values);
  231. break;
  232. case Zend_Db::FETCH_BOUND:
  233. $assoc = array_combine($this->_keys, $values);
  234. $row = array_merge($values, $assoc);
  235. $row = $this->_fetchBound($row);
  236. break;
  237. default:
  238. require_once 'Zend/Db/Statement/Sqlsrv/Exception.php';
  239. throw new Zend_Db_Statement_Sqlsrv_Exception("Invalid fetch mode '$style' specified");
  240. break;
  241. }
  242. return $row;
  243. }
  244. /**
  245. * Returns a single column from the next row of a result set.
  246. *
  247. * @param int $col OPTIONAL Position of the column to fetch.
  248. * @return string
  249. * @throws Zend_Db_Statement_Exception
  250. */
  251. public function fetchColumn($col = 0)
  252. {
  253. if (!$this->_stmt) {
  254. return false;
  255. }
  256. if (!sqlsrv_fetch($this->_stmt)) {
  257. if (null !== $error = sqlsrv_errors()) {
  258. require_once 'Zend/Db/Statement/Sqlsrv/Exception.php';
  259. throw new Zend_Db_Statement_Sqlsrv_Exception($error);
  260. }
  261. // If no error, there is simply no record
  262. return false;
  263. }
  264. $data = sqlsrv_get_field($this->_stmt, $col); //0-based
  265. if ($data === false) {
  266. require_once 'Zend/Db/Statement/Sqlsrv/Exception.php';
  267. throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors());
  268. }
  269. return $data;
  270. }
  271. /**
  272. * Fetches the next row and returns it as an object.
  273. *
  274. * @param string $class OPTIONAL Name of the class to create.
  275. * @param array $config OPTIONAL Constructor arguments for the class.
  276. * @return mixed One object instance of the specified class.
  277. * @throws Zend_Db_Statement_Exception
  278. */
  279. public function fetchObject($class = 'stdClass', array $config = array())
  280. {
  281. if (!$this->_stmt) {
  282. return false;
  283. }
  284. $obj = sqlsrv_fetch_object($this->_stmt);
  285. if ($error = sqlsrv_errors()) {
  286. require_once 'Zend/Db/Statement/Sqlsrv/Exception.php';
  287. throw new Zend_Db_Statement_Sqlsrv_Exception($error);
  288. }
  289. /* @todo XXX handle parameters */
  290. if (null === $obj) {
  291. return false;
  292. }
  293. return $obj;
  294. }
  295. /**
  296. * Returns metadata for a column in a result set.
  297. *
  298. * @param int $column
  299. * @return mixed
  300. * @throws Zend_Db_Statement_Sqlsrv_Exception
  301. */
  302. public function getColumnMeta($column)
  303. {
  304. $fields = sqlsrv_field_metadata($this->_stmt);
  305. if (!$fields) {
  306. throw new Zend_Db_Statement_Sqlsrv_Exception('Column metadata can not be fetched');
  307. }
  308. if (!isset($fields[$column])) {
  309. throw new Zend_Db_Statement_Sqlsrv_Exception('Column index does not exist in statement');
  310. }
  311. return $fields[$column];
  312. }
  313. /**
  314. * Retrieves the next rowset (result set) for a SQL statement that has
  315. * multiple result sets. An example is a stored procedure that returns
  316. * the results of multiple queries.
  317. *
  318. * @return bool
  319. * @throws Zend_Db_Statement_Exception
  320. */
  321. public function nextRowset()
  322. {
  323. if (sqlsrv_next_result($this->_stmt) === false) {
  324. require_once 'Zend/Db/Statement/Sqlsrv/Exception.php';
  325. throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors());
  326. }
  327. //else - moved to next (or there are no more rows)
  328. }
  329. /**
  330. * Returns the number of rows affected by the execution of the
  331. * last INSERT, DELETE, or UPDATE statement executed by this
  332. * statement object.
  333. *
  334. * @return int The number of rows affected.
  335. * @throws Zend_Db_Statement_Exception
  336. */
  337. public function rowCount()
  338. {
  339. if (!$this->_stmt) {
  340. return false;
  341. }
  342. if (!$this->_executed) {
  343. return 0;
  344. }
  345. $num_rows = sqlsrv_rows_affected($this->_stmt);
  346. // Strict check is necessary; 0 is a valid return value
  347. if ($num_rows === false) {
  348. require_once 'Zend/Db/Statement/Sqlsrv/Exception.php';
  349. throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors());
  350. }
  351. return $num_rows;
  352. }
  353. }