2
0

Oracle.php 17 KB

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