oci8_driver.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.1.6 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author EllisLab Dev Team
  9. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc.
  10. * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
  11. * @license http://codeigniter.com/user_guide/license.html
  12. * @link http://codeigniter.com
  13. * @since Version 1.0
  14. * @filesource
  15. */
  16. // ------------------------------------------------------------------------
  17. /**
  18. * oci8 Database Adapter Class
  19. *
  20. * Note: _DB is an extender class that the app controller
  21. * creates dynamically based on whether the active record
  22. * class is being used or not.
  23. *
  24. * @package CodeIgniter
  25. * @subpackage Drivers
  26. * @category Database
  27. * @author EllisLab Dev Team
  28. * @link http://codeigniter.com/user_guide/database/
  29. */
  30. /**
  31. * oci8 Database Adapter Class
  32. *
  33. * This is a modification of the DB_driver class to
  34. * permit access to oracle databases
  35. *
  36. * @author Kelly McArdle
  37. *
  38. */
  39. class CI_DB_oci8_driver extends CI_DB {
  40. var $dbdriver = 'oci8';
  41. // The character used for excaping
  42. var $_escape_char = '"';
  43. // clause and character used for LIKE escape sequences
  44. var $_like_escape_str = " escape '%s' ";
  45. var $_like_escape_chr = '!';
  46. /**
  47. * The syntax to count rows is slightly different across different
  48. * database engines, so this string appears in each driver and is
  49. * used for the count_all() and count_all_results() functions.
  50. */
  51. var $_count_string = "SELECT COUNT(1) AS ";
  52. var $_random_keyword = ' ASC'; // not currently supported
  53. // Set "auto commit" by default
  54. var $_commit = OCI_COMMIT_ON_SUCCESS;
  55. // need to track statement id and cursor id
  56. var $stmt_id;
  57. var $curs_id;
  58. // if we use a limit, we will add a field that will
  59. // throw off num_fields later
  60. var $limit_used;
  61. /**
  62. * Non-persistent database connection
  63. *
  64. * @access private called by the base class
  65. * @return resource
  66. */
  67. public function db_connect()
  68. {
  69. return @oci_connect($this->username, $this->password, $this->hostname, $this->char_set);
  70. }
  71. // --------------------------------------------------------------------
  72. /**
  73. * Persistent database connection
  74. *
  75. * @access private called by the base class
  76. * @return resource
  77. */
  78. public function db_pconnect()
  79. {
  80. return @oci_pconnect($this->username, $this->password, $this->hostname, $this->char_set);
  81. }
  82. // --------------------------------------------------------------------
  83. /**
  84. * Reconnect
  85. *
  86. * Keep / reestablish the db connection if no queries have been
  87. * sent for a length of time exceeding the server's idle timeout
  88. *
  89. * @access public
  90. * @return void
  91. */
  92. public function reconnect()
  93. {
  94. // not implemented in oracle
  95. return;
  96. }
  97. // --------------------------------------------------------------------
  98. /**
  99. * Select the database
  100. *
  101. * @access private called by the base class
  102. * @return resource
  103. */
  104. public function db_select()
  105. {
  106. // Not in Oracle - schemas are actually usernames
  107. return TRUE;
  108. }
  109. // --------------------------------------------------------------------
  110. /**
  111. * Set client character set
  112. *
  113. * @access public
  114. * @param string
  115. * @param string
  116. * @return resource
  117. */
  118. public function db_set_charset($charset, $collation)
  119. {
  120. // @todo - add support if needed
  121. return TRUE;
  122. }
  123. // --------------------------------------------------------------------
  124. /**
  125. * Version number query string
  126. *
  127. * @access protected
  128. * @return string
  129. */
  130. protected function _version()
  131. {
  132. return oci_server_version($this->conn_id);
  133. }
  134. // --------------------------------------------------------------------
  135. /**
  136. * Execute the query
  137. *
  138. * @access protected called by the base class
  139. * @param string an SQL query
  140. * @return resource
  141. */
  142. protected function _execute($sql)
  143. {
  144. // oracle must parse the query before it is run. All of the actions with
  145. // the query are based on the statement id returned by ociparse
  146. $this->stmt_id = FALSE;
  147. $this->_set_stmt_id($sql);
  148. oci_set_prefetch($this->stmt_id, 1000);
  149. return @oci_execute($this->stmt_id, $this->_commit);
  150. }
  151. /**
  152. * Generate a statement ID
  153. *
  154. * @access private
  155. * @param string an SQL query
  156. * @return none
  157. */
  158. private function _set_stmt_id($sql)
  159. {
  160. if ( ! is_resource($this->stmt_id))
  161. {
  162. $this->stmt_id = oci_parse($this->conn_id, $this->_prep_query($sql));
  163. }
  164. }
  165. // --------------------------------------------------------------------
  166. /**
  167. * Prep the query
  168. *
  169. * If needed, each database adapter can prep the query string
  170. *
  171. * @access private called by execute()
  172. * @param string an SQL query
  173. * @return string
  174. */
  175. private function _prep_query($sql)
  176. {
  177. return $sql;
  178. }
  179. // --------------------------------------------------------------------
  180. /**
  181. * getCursor. Returns a cursor from the datbase
  182. *
  183. * @access public
  184. * @return cursor id
  185. */
  186. public function get_cursor()
  187. {
  188. $this->curs_id = oci_new_cursor($this->conn_id);
  189. return $this->curs_id;
  190. }
  191. // --------------------------------------------------------------------
  192. /**
  193. * Stored Procedure. Executes a stored procedure
  194. *
  195. * @access public
  196. * @param package package stored procedure is in
  197. * @param procedure stored procedure to execute
  198. * @param params array of parameters
  199. * @return array
  200. *
  201. * params array keys
  202. *
  203. * KEY OPTIONAL NOTES
  204. * name no the name of the parameter should be in :<param_name> format
  205. * value no the value of the parameter. If this is an OUT or IN OUT parameter,
  206. * this should be a reference to a variable
  207. * type yes the type of the parameter
  208. * length yes the max size of the parameter
  209. */
  210. public function stored_procedure($package, $procedure, $params)
  211. {
  212. if ($package == '' OR $procedure == '' OR ! is_array($params))
  213. {
  214. if ($this->db_debug)
  215. {
  216. log_message('error', 'Invalid query: '.$package.'.'.$procedure);
  217. return $this->display_error('db_invalid_query');
  218. }
  219. return FALSE;
  220. }
  221. // build the query string
  222. $sql = "begin $package.$procedure(";
  223. $have_cursor = FALSE;
  224. foreach ($params as $param)
  225. {
  226. $sql .= $param['name'] . ",";
  227. if (array_key_exists('type', $param) && ($param['type'] === OCI_B_CURSOR))
  228. {
  229. $have_cursor = TRUE;
  230. }
  231. }
  232. $sql = trim($sql, ",") . "); end;";
  233. $this->stmt_id = FALSE;
  234. $this->_set_stmt_id($sql);
  235. $this->_bind_params($params);
  236. $this->query($sql, FALSE, $have_cursor);
  237. }
  238. // --------------------------------------------------------------------
  239. /**
  240. * Bind parameters
  241. *
  242. * @access private
  243. * @return none
  244. */
  245. private function _bind_params($params)
  246. {
  247. if ( ! is_array($params) OR ! is_resource($this->stmt_id))
  248. {
  249. return;
  250. }
  251. foreach ($params as $param)
  252. {
  253. foreach (array('name', 'value', 'type', 'length') as $val)
  254. {
  255. if ( ! isset($param[$val]))
  256. {
  257. $param[$val] = '';
  258. }
  259. }
  260. oci_bind_by_name($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']);
  261. }
  262. }
  263. // --------------------------------------------------------------------
  264. /**
  265. * Begin Transaction
  266. *
  267. * @access public
  268. * @return bool
  269. */
  270. public function trans_begin($test_mode = FALSE)
  271. {
  272. if ( ! $this->trans_enabled)
  273. {
  274. return TRUE;
  275. }
  276. // When transactions are nested we only begin/commit/rollback the outermost ones
  277. if ($this->_trans_depth > 0)
  278. {
  279. return TRUE;
  280. }
  281. // Reset the transaction failure flag.
  282. // If the $test_mode flag is set to TRUE transactions will be rolled back
  283. // even if the queries produce a successful result.
  284. $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
  285. $this->_commit = OCI_DEFAULT;
  286. return TRUE;
  287. }
  288. // --------------------------------------------------------------------
  289. /**
  290. * Commit Transaction
  291. *
  292. * @access public
  293. * @return bool
  294. */
  295. public function trans_commit()
  296. {
  297. if ( ! $this->trans_enabled)
  298. {
  299. return TRUE;
  300. }
  301. // When transactions are nested we only begin/commit/rollback the outermost ones
  302. if ($this->_trans_depth > 0)
  303. {
  304. return TRUE;
  305. }
  306. $ret = oci_commit($this->conn_id);
  307. $this->_commit = OCI_COMMIT_ON_SUCCESS;
  308. return $ret;
  309. }
  310. // --------------------------------------------------------------------
  311. /**
  312. * Rollback Transaction
  313. *
  314. * @access public
  315. * @return bool
  316. */
  317. public function trans_rollback()
  318. {
  319. if ( ! $this->trans_enabled)
  320. {
  321. return TRUE;
  322. }
  323. // When transactions are nested we only begin/commit/rollback the outermost ones
  324. if ($this->_trans_depth > 0)
  325. {
  326. return TRUE;
  327. }
  328. $ret = oci_rollback($this->conn_id);
  329. $this->_commit = OCI_COMMIT_ON_SUCCESS;
  330. return $ret;
  331. }
  332. // --------------------------------------------------------------------
  333. /**
  334. * Escape String
  335. *
  336. * @access public
  337. * @param string
  338. * @param bool whether or not the string will be used in a LIKE condition
  339. * @return string
  340. */
  341. public function escape_str($str, $like = FALSE)
  342. {
  343. if (is_array($str))
  344. {
  345. foreach ($str as $key => $val)
  346. {
  347. $str[$key] = $this->escape_str($val, $like);
  348. }
  349. return $str;
  350. }
  351. $str = remove_invisible_characters($str);
  352. // escape LIKE condition wildcards
  353. if ($like === TRUE)
  354. {
  355. $str = str_replace( array('%', '_', $this->_like_escape_chr),
  356. array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
  357. $str);
  358. }
  359. return $str;
  360. }
  361. // --------------------------------------------------------------------
  362. /**
  363. * Affected Rows
  364. *
  365. * @access public
  366. * @return integer
  367. */
  368. public function affected_rows()
  369. {
  370. return @oci_num_rows($this->stmt_id);
  371. }
  372. // --------------------------------------------------------------------
  373. /**
  374. * Insert ID
  375. *
  376. * @access public
  377. * @return integer
  378. */
  379. public function insert_id()
  380. {
  381. // not supported in oracle
  382. return $this->display_error('db_unsupported_function');
  383. }
  384. // --------------------------------------------------------------------
  385. /**
  386. * "Count All" query
  387. *
  388. * Generates a platform-specific query string that counts all records in
  389. * the specified database
  390. *
  391. * @access public
  392. * @param string
  393. * @return string
  394. */
  395. public function count_all($table = '')
  396. {
  397. if ($table == '')
  398. {
  399. return 0;
  400. }
  401. $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
  402. if ($query == FALSE)
  403. {
  404. return 0;
  405. }
  406. $row = $query->row();
  407. $this->_reset_select();
  408. return (int) $row->numrows;
  409. }
  410. // --------------------------------------------------------------------
  411. /**
  412. * Show table query
  413. *
  414. * Generates a platform-specific query string so that the table names can be fetched
  415. *
  416. * @access protected
  417. * @param boolean
  418. * @return string
  419. */
  420. protected function _list_tables($prefix_limit = FALSE)
  421. {
  422. $sql = "SELECT TABLE_NAME FROM ALL_TABLES";
  423. if ($prefix_limit !== FALSE AND $this->dbprefix != '')
  424. {
  425. $sql .= " WHERE TABLE_NAME LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
  426. }
  427. return $sql;
  428. }
  429. // --------------------------------------------------------------------
  430. /**
  431. * Show column query
  432. *
  433. * Generates a platform-specific query string so that the column names can be fetched
  434. *
  435. * @access protected
  436. * @param string the table name
  437. * @return string
  438. */
  439. protected function _list_columns($table = '')
  440. {
  441. return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$table'";
  442. }
  443. // --------------------------------------------------------------------
  444. /**
  445. * Field data query
  446. *
  447. * Generates a platform-specific query so that the column data can be retrieved
  448. *
  449. * @access public
  450. * @param string the table name
  451. * @return object
  452. */
  453. protected function _field_data($table)
  454. {
  455. return "SELECT * FROM ".$table." where rownum = 1";
  456. }
  457. // --------------------------------------------------------------------
  458. /**
  459. * The error message string
  460. *
  461. * @access protected
  462. * @return string
  463. */
  464. protected function _error_message()
  465. {
  466. // If the error was during connection, no conn_id should be passed
  467. $error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error();
  468. return $error['message'];
  469. }
  470. // --------------------------------------------------------------------
  471. /**
  472. * The error message number
  473. *
  474. * @access protected
  475. * @return integer
  476. */
  477. protected function _error_number()
  478. {
  479. // Same as _error_message()
  480. $error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error();
  481. return $error['code'];
  482. }
  483. // --------------------------------------------------------------------
  484. /**
  485. * Escape the SQL Identifiers
  486. *
  487. * This function escapes column and table names
  488. *
  489. * @access protected
  490. * @param string
  491. * @return string
  492. */
  493. protected function _escape_identifiers($item)
  494. {
  495. if ($this->_escape_char == '')
  496. {
  497. return $item;
  498. }
  499. foreach ($this->_reserved_identifiers as $id)
  500. {
  501. if (strpos($item, '.'.$id) !== FALSE)
  502. {
  503. $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
  504. // remove duplicates if the user already included the escape
  505. return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
  506. }
  507. }
  508. if (strpos($item, '.') !== FALSE)
  509. {
  510. $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
  511. }
  512. else
  513. {
  514. $str = $this->_escape_char.$item.$this->_escape_char;
  515. }
  516. // remove duplicates if the user already included the escape
  517. return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
  518. }
  519. // --------------------------------------------------------------------
  520. /**
  521. * From Tables
  522. *
  523. * This function implicitly groups FROM tables so there is no confusion
  524. * about operator precedence in harmony with SQL standards
  525. *
  526. * @access protected
  527. * @param type
  528. * @return type
  529. */
  530. protected function _from_tables($tables)
  531. {
  532. if ( ! is_array($tables))
  533. {
  534. $tables = array($tables);
  535. }
  536. return implode(', ', $tables);
  537. }
  538. // --------------------------------------------------------------------
  539. /**
  540. * Insert statement
  541. *
  542. * Generates a platform-specific insert string from the supplied data
  543. *
  544. * @access public
  545. * @param string the table name
  546. * @param array the insert keys
  547. * @param array the insert values
  548. * @return string
  549. */
  550. protected function _insert($table, $keys, $values)
  551. {
  552. return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
  553. }
  554. // --------------------------------------------------------------------
  555. /**
  556. * Insert_batch statement
  557. *
  558. * Generates a platform-specific insert string from the supplied data
  559. *
  560. * @access protected
  561. * @param string the table name
  562. * @param array the insert keys
  563. * @param array the insert values
  564. * @return string
  565. */
  566. protected function _insert_batch($table, $keys, $values)
  567. {
  568. $keys = implode(', ', $keys);
  569. $sql = "INSERT ALL\n";
  570. for ($i = 0, $c = count($values); $i < $c; $i++)
  571. {
  572. $sql .= ' INTO ' . $table . ' (' . $keys . ') VALUES ' . $values[$i] . "\n";
  573. }
  574. $sql .= 'SELECT * FROM dual';
  575. return $sql;
  576. }
  577. // --------------------------------------------------------------------
  578. /**
  579. * Update statement
  580. *
  581. * Generates a platform-specific update string from the supplied data
  582. *
  583. * @access protected
  584. * @param string the table name
  585. * @param array the update data
  586. * @param array the where clause
  587. * @param array the orderby clause
  588. * @param array the limit clause
  589. * @return string
  590. */
  591. protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
  592. {
  593. foreach ($values as $key => $val)
  594. {
  595. $valstr[] = $key." = ".$val;
  596. }
  597. $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
  598. $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
  599. $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
  600. $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
  601. $sql .= $orderby.$limit;
  602. return $sql;
  603. }
  604. // --------------------------------------------------------------------
  605. /**
  606. * Truncate statement
  607. *
  608. * Generates a platform-specific truncate string from the supplied data
  609. * If the database does not support the truncate() command
  610. * This function maps to "DELETE FROM table"
  611. *
  612. * @access protected
  613. * @param string the table name
  614. * @return string
  615. */
  616. protected function _truncate($table)
  617. {
  618. return "TRUNCATE TABLE ".$table;
  619. }
  620. // --------------------------------------------------------------------
  621. /**
  622. * Delete statement
  623. *
  624. * Generates a platform-specific delete string from the supplied data
  625. *
  626. * @access protected
  627. * @param string the table name
  628. * @param array the where clause
  629. * @param string the limit clause
  630. * @return string
  631. */
  632. protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
  633. {
  634. $conditions = '';
  635. if (count($where) > 0 OR count($like) > 0)
  636. {
  637. $conditions = "\nWHERE ";
  638. $conditions .= implode("\n", $this->ar_where);
  639. if (count($where) > 0 && count($like) > 0)
  640. {
  641. $conditions .= " AND ";
  642. }
  643. $conditions .= implode("\n", $like);
  644. }
  645. $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
  646. return "DELETE FROM ".$table.$conditions.$limit;
  647. }
  648. // --------------------------------------------------------------------
  649. /**
  650. * Limit string
  651. *
  652. * Generates a platform-specific LIMIT clause
  653. *
  654. * @access protected
  655. * @param string the sql query string
  656. * @param integer the number of rows to limit the query to
  657. * @param integer the offset value
  658. * @return string
  659. */
  660. protected function _limit($sql, $limit, $offset)
  661. {
  662. $limit = $offset + $limit;
  663. $newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)";
  664. if ($offset != 0)
  665. {
  666. $newsql .= " WHERE rnum >= $offset";
  667. }
  668. // remember that we used limits
  669. $this->limit_used = TRUE;
  670. return $newsql;
  671. }
  672. // --------------------------------------------------------------------
  673. /**
  674. * Close DB Connection
  675. *
  676. * @access protected
  677. * @param resource
  678. * @return void
  679. */
  680. protected function _close($conn_id)
  681. {
  682. @oci_close($conn_id);
  683. }
  684. }
  685. /* End of file oci8_driver.php */
  686. /* Location: ./system/database/drivers/oci8/oci8_driver.php */