2
0

Oracle.php 17 KB

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