PageRenderTime 64ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/library/Zend/Db/Statement/Oracle.php

http://github.com/zendframework/zf2
PHP | 517 lines | 296 code | 62 blank | 159 comment | 54 complexity | ddab1bf5072157d81d4d883f64fdf2c6 MD5 | raw file
Possible License(s): BSD-3-Clause
  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-2012 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /**
  22. * @namespace
  23. */
  24. namespace Zend\Db\Statement;
  25. /**
  26. * Extends for Oracle.
  27. *
  28. * @uses \Zend\Db\Statement\AbstractStatement
  29. * @uses \Zend\Db\Statement\OracleException
  30. * @category Zend
  31. * @package Zend_Db
  32. * @subpackage Statement
  33. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  34. * @license http://framework.zend.com/license/new-bsd New BSD License
  35. */
  36. class Oracle extends AbstractStatement
  37. {
  38. /**
  39. * Column names.
  40. */
  41. protected $_keys;
  42. /**
  43. * Fetched result values.
  44. */
  45. protected $_values;
  46. /**
  47. * Check if LOB field are returned as string
  48. * instead of Oci-Lob object
  49. *
  50. * @var boolean
  51. */
  52. protected $_lobAsString = false;
  53. /**
  54. * Activate/deactivate return of LOB as string
  55. *
  56. * @param string $lob_as_string
  57. * @return \Zend\Db\Statement\Oracle
  58. */
  59. public function setLobAsString($lob_as_string)
  60. {
  61. $this->_lobAsString = (bool) $lob_as_string;
  62. return $this;
  63. }
  64. /**
  65. * Return whether or not LOB are returned as string
  66. *
  67. * @return boolean
  68. */
  69. public function getLobAsString()
  70. {
  71. return $this->_lobAsString;
  72. }
  73. /**
  74. * Prepares statement handle
  75. *
  76. * @param string $sql
  77. * @return void
  78. * @throws \Zend\Db\Statement\OracleException
  79. */
  80. protected function _prepare($sql)
  81. {
  82. $connection = $this->_adapter->getConnection();
  83. $this->_stmt = oci_parse($connection, $sql);
  84. if (!$this->_stmt) {
  85. throw new OracleException(oci_error($connection));
  86. }
  87. }
  88. /**
  89. * Binds a parameter to the specified variable name.
  90. *
  91. * @param mixed $parameter Name the parameter, either integer or string.
  92. * @param mixed $variable Reference to PHP variable containing the value.
  93. * @param mixed $type OPTIONAL Datatype of SQL parameter.
  94. * @param mixed $length OPTIONAL Length of SQL parameter.
  95. * @param mixed $options OPTIONAL Other options.
  96. * @return bool
  97. * @throws \Zend\Db\Statement\Exception
  98. */
  99. protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null)
  100. {
  101. // default value
  102. if ($type === NULL) {
  103. $type = SQLT_CHR;
  104. }
  105. // default value
  106. if ($length === NULL) {
  107. $length = -1;
  108. }
  109. $retval = @oci_bind_by_name($this->_stmt, $parameter, $variable, $length, $type);
  110. if ($retval === false) {
  111. throw new OracleException(oci_error($this->_stmt));
  112. }
  113. return true;
  114. }
  115. /**
  116. * Closes the cursor, allowing the statement to be executed again.
  117. *
  118. * @return bool
  119. */
  120. public function closeCursor()
  121. {
  122. if (!$this->_stmt) {
  123. return false;
  124. }
  125. oci_free_statement($this->_stmt);
  126. $this->_stmt = false;
  127. return true;
  128. }
  129. /**
  130. * Returns the number of columns in the result set.
  131. * Returns null if the statement has no result set metadata.
  132. *
  133. * @return int The number of columns.
  134. */
  135. public function columnCount()
  136. {
  137. if (!$this->_stmt) {
  138. return false;
  139. }
  140. return oci_num_fields($this->_stmt);
  141. }
  142. /**
  143. * Retrieves the error code, if any, associated with the last operation on
  144. * the statement handle.
  145. *
  146. * @return string error code.
  147. */
  148. public function errorCode()
  149. {
  150. if (!$this->_stmt) {
  151. return false;
  152. }
  153. $error = oci_error($this->_stmt);
  154. if (!$error) {
  155. return false;
  156. }
  157. return $error['code'];
  158. }
  159. /**
  160. * Retrieves an array of error information, if any, associated with the
  161. * last operation on the statement handle.
  162. *
  163. * @return array
  164. */
  165. public function errorInfo()
  166. {
  167. if (!$this->_stmt) {
  168. return false;
  169. }
  170. $error = oci_error($this->_stmt);
  171. if (!$error) {
  172. return false;
  173. }
  174. if (isset($error['sqltext'])) {
  175. return array(
  176. $error['code'],
  177. $error['message'],
  178. $error['offset'],
  179. $error['sqltext'],
  180. );
  181. } else {
  182. return array(
  183. $error['code'],
  184. $error['message'],
  185. );
  186. }
  187. }
  188. /**
  189. * Executes a prepared statement.
  190. *
  191. * @param array $params OPTIONAL Values to bind to parameter placeholders.
  192. * @return bool
  193. * @throws \Zend\Db\Statement\Exception
  194. */
  195. public function _execute(array $params = null)
  196. {
  197. $connection = $this->_adapter->getConnection();
  198. if (!$this->_stmt) {
  199. return false;
  200. }
  201. if ($params !== null) {
  202. if (!is_array($params)) {
  203. $params = array($params);
  204. }
  205. $error = false;
  206. foreach (array_keys($params) as $name) {
  207. if (!@oci_bind_by_name($this->_stmt, $name, $params[$name], -1)) {
  208. $error = true;
  209. break;
  210. }
  211. }
  212. if ($error) {
  213. throw new OracleException(oci_error($this->_stmt));
  214. }
  215. }
  216. $retval = @oci_execute($this->_stmt, $this->_adapter->_getExecuteMode());
  217. if ($retval === false) {
  218. throw new OracleException(oci_error($this->_stmt));
  219. }
  220. $this->_keys = Array();
  221. if ($field_num = oci_num_fields($this->_stmt)) {
  222. for ($i = 1; $i <= $field_num; $i++) {
  223. $name = oci_field_name($this->_stmt, $i);
  224. $this->_keys[] = $name;
  225. }
  226. }
  227. $this->_values = Array();
  228. if ($this->_keys) {
  229. $this->_values = array_fill(0, count($this->_keys), null);
  230. }
  231. return $retval;
  232. }
  233. /**
  234. * Fetches a row from the result set.
  235. *
  236. * @param int $style OPTIONAL Fetch mode for this fetch operation.
  237. * @param int $cursor OPTIONAL Absolute, relative, or other.
  238. * @param int $offset OPTIONAL Number for absolute or relative cursors.
  239. * @return mixed Array, object, or scalar depending on fetch mode.
  240. * @throws \Zend\Db\Statement\Exception
  241. */
  242. public function fetch($style = null, $cursor = null, $offset = null)
  243. {
  244. if (!$this->_stmt) {
  245. return false;
  246. }
  247. if ($style === null) {
  248. $style = $this->_fetchMode;
  249. }
  250. $lob_as_string = $this->getLobAsString() ? Oci_RETURN_LOBS : 0;
  251. switch ($style) {
  252. case Db\Db::FETCH_NUM:
  253. $row = oci_fetch_array($this->_stmt, Oci_NUM | Oci_RETURN_NULLS | $lob_as_string);
  254. break;
  255. case Db\Db::FETCH_ASSOC:
  256. $row = oci_fetch_array($this->_stmt, Oci_ASSOC | Oci_RETURN_NULLS | $lob_as_string);
  257. break;
  258. case Db\Db::FETCH_BOTH:
  259. $row = oci_fetch_array($this->_stmt, Oci_BOTH | Oci_RETURN_NULLS | $lob_as_string);
  260. break;
  261. case Db\Db::FETCH_OBJ:
  262. $row = oci_fetch_object($this->_stmt);
  263. break;
  264. case Db\Db::FETCH_BOUND:
  265. $row = oci_fetch_array($this->_stmt, Oci_BOTH | Oci_RETURN_NULLS | $lob_as_string);
  266. if ($row !== false) {
  267. return $this->_fetchBound($row);
  268. }
  269. break;
  270. default:
  271. throw new OracleException(
  272. array(
  273. 'code' => 'HYC00',
  274. 'message' => "Invalid fetch mode '$style' specified"
  275. )
  276. );
  277. break;
  278. }
  279. if (! $row && $error = oci_error($this->_stmt)) {
  280. throw new OracleException($error);
  281. }
  282. if (is_array($row) && array_key_exists('zend_db_rownum', $row)) {
  283. unset($row['zend_db_rownum']);
  284. }
  285. return $row;
  286. }
  287. /**
  288. * Returns an array containing all of the result set rows.
  289. *
  290. * @param int $style OPTIONAL Fetch mode.
  291. * @param int $col OPTIONAL Column number, if fetch mode is by column.
  292. * @return array Collection of rows, each in a format by the fetch mode.
  293. * @throws \Zend\Db\Statement\Exception
  294. */
  295. public function fetchAll($style = null, $col = 0)
  296. {
  297. if (!$this->_stmt) {
  298. return false;
  299. }
  300. // make sure we have a fetch mode
  301. if ($style === null) {
  302. $style = $this->_fetchMode;
  303. }
  304. $flags = Oci_FETCHSTATEMENT_BY_ROW;
  305. switch ($style) {
  306. case Db\Db::FETCH_BOTH:
  307. throw new OracleException(
  308. array(
  309. 'code' => 'HYC00',
  310. 'message' => "Oci8 driver does not support fetchAll(FETCH_BOTH), use fetch() in a loop instead"
  311. )
  312. );
  313. // notreached
  314. $flags |= Oci_NUM;
  315. $flags |= Oci_ASSOC;
  316. break;
  317. case Db\Db::FETCH_NUM:
  318. $flags |= Oci_NUM;
  319. break;
  320. case Db\Db::FETCH_ASSOC:
  321. $flags |= Oci_ASSOC;
  322. break;
  323. case Db\Db::FETCH_OBJ:
  324. break;
  325. case Db\Db::FETCH_COLUMN:
  326. $flags = $flags &~ Oci_FETCHSTATEMENT_BY_ROW;
  327. $flags |= Oci_FETCHSTATEMENT_BY_COLUMN;
  328. $flags |= Oci_NUM;
  329. break;
  330. default:
  331. throw new OracleException(
  332. array(
  333. 'code' => 'HYC00',
  334. 'message' => "Invalid fetch mode '$style' specified"
  335. )
  336. );
  337. break;
  338. }
  339. $result = Array();
  340. if ($flags != Oci_FETCHSTATEMENT_BY_ROW) { /* not Zend_Db::FETCH_OBJ */
  341. if (! ($rows = oci_fetch_all($this->_stmt, $result, 0, -1, $flags) )) {
  342. if ($error = oci_error($this->_stmt)) {
  343. throw new OracleException($error);
  344. }
  345. if (!$rows) {
  346. return array();
  347. }
  348. }
  349. if ($style == Db\Db::FETCH_COLUMN) {
  350. $result = $result[$col];
  351. }
  352. foreach ($result as &$row) {
  353. if (is_array($row) && array_key_exists('zend_db_rownum', $row)) {
  354. unset($row['zend_db_rownum']);
  355. }
  356. }
  357. } else {
  358. while (($row = oci_fetch_object($this->_stmt)) !== false) {
  359. $result [] = $row;
  360. }
  361. if ($error = oci_error($this->_stmt)) {
  362. throw new OracleException($error);
  363. }
  364. }
  365. return $result;
  366. }
  367. /**
  368. * Returns a single column from the next row of a result set.
  369. *
  370. * @param int $col OPTIONAL Position of the column to fetch.
  371. * @return string
  372. * @throws \Zend\Db\Statement\Exception
  373. */
  374. public function fetchColumn($col = 0)
  375. {
  376. if (!$this->_stmt) {
  377. return false;
  378. }
  379. if (!oci_fetch($this->_stmt)) {
  380. // if no error, there is simply no record
  381. if (!$error = oci_error($this->_stmt)) {
  382. return false;
  383. }
  384. throw new OracleException($error);
  385. }
  386. $data = oci_result($this->_stmt, $col+1); //1-based
  387. if ($data === false) {
  388. throw new OracleException(oci_error($this->_stmt));
  389. }
  390. if ($this->getLobAsString()) {
  391. // instanceof doesn't allow '-', we must use a temporary string
  392. $type = 'Oci-Lob';
  393. if ($data instanceof $type) {
  394. $data = $data->read($data->size());
  395. }
  396. }
  397. return $data;
  398. }
  399. /**
  400. * Fetches the next row and returns it as an object.
  401. *
  402. * @param string $class OPTIONAL Name of the class to create.
  403. * @param array $config OPTIONAL Constructor arguments for the class.
  404. * @return mixed One object instance of the specified class.
  405. * @throws \Zend\Db\Statement\Exception
  406. */
  407. public function fetchObject($class = 'stdClass', array $config = array())
  408. {
  409. if (!$this->_stmt) {
  410. return false;
  411. }
  412. $obj = oci_fetch_object($this->_stmt);
  413. if ($error = oci_error($this->_stmt)) {
  414. throw new OracleException($error);
  415. }
  416. /* @todo XXX handle parameters */
  417. return $obj;
  418. }
  419. /**
  420. * Retrieves the next rowset (result set) for a SQL statement that has
  421. * multiple result sets. An example is a stored procedure that returns
  422. * the results of multiple queries.
  423. *
  424. * @return bool
  425. * @throws \Zend\Db\Statement\Exception
  426. */
  427. public function nextRowset()
  428. {
  429. throw new OracleException(
  430. array(
  431. 'code' => 'HYC00',
  432. 'message' => 'Optional feature not implemented'
  433. )
  434. );
  435. }
  436. /**
  437. * Returns the number of rows affected by the execution of the
  438. * last INSERT, DELETE, or UPDATE statement executed by this
  439. * statement object.
  440. *
  441. * @return int The number of rows affected.
  442. * @throws \Zend\Db\Statement\Exception
  443. */
  444. public function rowCount()
  445. {
  446. if (!$this->_stmt) {
  447. return false;
  448. }
  449. $num_rows = oci_num_rows($this->_stmt);
  450. if ($num_rows === false) {
  451. throw new OracleException(oci_error($this->_stmt));
  452. }
  453. return $num_rows;
  454. }
  455. }