PageRenderTime 28ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/phpBB/phpbb/db/driver/oracle.php

http://github.com/phpbb/phpbb
PHP | 821 lines | 652 code | 40 blank | 129 comment | 52 complexity | aa184dcbc0cd34329795145f37cca6bf MD5 | raw file
Possible License(s): GPL-3.0, AGPL-1.0
  1. <?php
  2. /**
  3. *
  4. * This file is part of the phpBB Forum Software package.
  5. *
  6. * @copyright (c) phpBB Limited <https://www.phpbb.com>
  7. * @license GNU General Public License, version 2 (GPL-2.0)
  8. *
  9. * For full copyright and license information, please see
  10. * the docs/CREDITS.txt file.
  11. *
  12. */
  13. namespace phpbb\db\driver;
  14. /**
  15. * Oracle Database Abstraction Layer
  16. */
  17. class oracle extends \phpbb\db\driver\driver
  18. {
  19. var $last_query_text = '';
  20. var $connect_error = '';
  21. /**
  22. * {@inheritDoc}
  23. */
  24. function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
  25. {
  26. $this->persistency = $persistency;
  27. $this->user = $sqluser;
  28. $this->server = $sqlserver . (($port) ? ':' . $port : '');
  29. $this->dbname = $database;
  30. $connect = $database;
  31. // support for "easy connect naming"
  32. if ($sqlserver !== '' && $sqlserver !== '/')
  33. {
  34. if (substr($sqlserver, -1, 1) == '/')
  35. {
  36. $sqlserver == substr($sqlserver, 0, -1);
  37. }
  38. $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database;
  39. }
  40. if ($new_link)
  41. {
  42. if (!function_exists('ocinlogon'))
  43. {
  44. $this->connect_error = 'ocinlogon function does not exist, is oci extension installed?';
  45. return $this->sql_error('');
  46. }
  47. $this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8');
  48. }
  49. else if ($this->persistency)
  50. {
  51. if (!function_exists('ociplogon'))
  52. {
  53. $this->connect_error = 'ociplogon function does not exist, is oci extension installed?';
  54. return $this->sql_error('');
  55. }
  56. $this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8');
  57. }
  58. else
  59. {
  60. if (!function_exists('ocilogon'))
  61. {
  62. $this->connect_error = 'ocilogon function does not exist, is oci extension installed?';
  63. return $this->sql_error('');
  64. }
  65. $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8');
  66. }
  67. return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
  68. }
  69. /**
  70. * {@inheritDoc}
  71. */
  72. function sql_server_info($raw = false, $use_cache = true)
  73. {
  74. /**
  75. * force $use_cache false. I didn't research why the caching code below is commented out
  76. * but I assume its because the Oracle extension provides a direct method to access it
  77. * without a query.
  78. */
  79. /*
  80. global $cache;
  81. if (empty($cache) || ($this->sql_server_version = $cache->get('oracle_version')) === false)
  82. {
  83. $result = @ociparse($this->db_connect_id, 'SELECT * FROM v$version WHERE banner LIKE \'Oracle%\'');
  84. @ociexecute($result, OCI_DEFAULT);
  85. @ocicommit($this->db_connect_id);
  86. $row = array();
  87. @ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS);
  88. @ocifreestatement($result);
  89. $this->sql_server_version = trim($row['BANNER']);
  90. $cache->put('oracle_version', $this->sql_server_version);
  91. }
  92. */
  93. $this->sql_server_version = @ociserverversion($this->db_connect_id);
  94. return $this->sql_server_version;
  95. }
  96. /**
  97. * SQL Transaction
  98. * @access private
  99. */
  100. function _sql_transaction($status = 'begin')
  101. {
  102. switch ($status)
  103. {
  104. case 'begin':
  105. return true;
  106. break;
  107. case 'commit':
  108. return @ocicommit($this->db_connect_id);
  109. break;
  110. case 'rollback':
  111. return @ocirollback($this->db_connect_id);
  112. break;
  113. }
  114. return true;
  115. }
  116. /**
  117. * Oracle specific code to handle the fact that it does not compare columns properly
  118. * @access private
  119. */
  120. function _rewrite_col_compare($args)
  121. {
  122. if (count($args) == 4)
  123. {
  124. if ($args[2] == '=')
  125. {
  126. return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))';
  127. }
  128. else if ($args[2] == '<>')
  129. {
  130. // really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P
  131. return '(' . $args[0] . ' OR ((' . $args[1] . ' is NULL AND ' . $args[3] . ' is NOT NULL) OR (' . $args[1] . ' is NOT NULL AND ' . $args[3] . ' is NULL)))';
  132. }
  133. }
  134. else
  135. {
  136. return $this->_rewrite_where($args[0]);
  137. }
  138. }
  139. /**
  140. * Oracle specific code to handle it's lack of sanity
  141. * @access private
  142. */
  143. function _rewrite_where($where_clause)
  144. {
  145. preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER);
  146. $out = '';
  147. foreach ($result as $val)
  148. {
  149. if (!isset($val[5]))
  150. {
  151. if ($val[4] !== "''")
  152. {
  153. $out .= $val[0];
  154. }
  155. else
  156. {
  157. $out .= ' ' . $val[1] . ' ' . $val[2];
  158. if ($val[3] == '=')
  159. {
  160. $out .= ' is NULL';
  161. }
  162. else if ($val[3] == '<>')
  163. {
  164. $out .= ' is NOT NULL';
  165. }
  166. }
  167. }
  168. else
  169. {
  170. $in_clause = array();
  171. $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1);
  172. $extra = false;
  173. preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER);
  174. $i = 0;
  175. foreach ($sub_vals[0] as $sub_val)
  176. {
  177. // two things:
  178. // 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison
  179. // 2) This fixes the 1000 list limit that Oracle has (ORA-01795)
  180. if ($sub_val !== "''")
  181. {
  182. $in_clause[(int) $i++/1000][] = $sub_val;
  183. }
  184. else
  185. {
  186. $extra = true;
  187. }
  188. }
  189. if (!$extra && $i < 1000)
  190. {
  191. $out .= $val[0];
  192. }
  193. else
  194. {
  195. $out .= ' ' . $val[1] . '(';
  196. $in_array = array();
  197. // constuct each IN() clause
  198. foreach ($in_clause as $in_values)
  199. {
  200. $in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')';
  201. }
  202. // Join the IN() clauses against a few ORs (IN is just a nicer OR anyway)
  203. $out .= implode(' OR ', $in_array);
  204. // handle the empty string case
  205. if ($extra)
  206. {
  207. $out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL';
  208. }
  209. $out .= ')';
  210. unset($in_array, $in_clause);
  211. }
  212. }
  213. }
  214. return $out;
  215. }
  216. /**
  217. * {@inheritDoc}
  218. */
  219. function sql_query($query = '', $cache_ttl = 0)
  220. {
  221. if ($query != '')
  222. {
  223. global $cache;
  224. if ($this->debug_sql_explain)
  225. {
  226. $this->sql_report('start', $query);
  227. }
  228. else if ($this->debug_load_time)
  229. {
  230. $this->curtime = microtime(true);
  231. }
  232. $this->last_query_text = $query;
  233. $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
  234. $this->sql_add_num_queries($this->query_result);
  235. if ($this->query_result === false)
  236. {
  237. $in_transaction = false;
  238. if (!$this->transaction)
  239. {
  240. $this->sql_transaction('begin');
  241. }
  242. else
  243. {
  244. $in_transaction = true;
  245. }
  246. $array = array();
  247. // We overcome Oracle's 4000 char limit by binding vars
  248. if (strlen($query) > 4000)
  249. {
  250. if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/sU', $query, $regs))
  251. {
  252. if (strlen($regs[3]) > 4000)
  253. {
  254. $cols = explode(', ', $regs[2]);
  255. preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER);
  256. /* The code inside this comment block breaks clob handling, but does allow the
  257. database restore script to work. If you want to allow no posts longer than 4KB
  258. and/or need the db restore script, uncomment this.
  259. if (count($cols) !== count($vals))
  260. {
  261. // Try to replace some common data we know is from our restore script or from other sources
  262. $regs[3] = str_replace("'||chr(47)||'", '/', $regs[3]);
  263. $_vals = explode(', ', $regs[3]);
  264. $vals = array();
  265. $is_in_val = false;
  266. $i = 0;
  267. $string = '';
  268. foreach ($_vals as $value)
  269. {
  270. if (strpos($value, "'") === false && !$is_in_val)
  271. {
  272. $vals[$i++] = $value;
  273. continue;
  274. }
  275. if (substr($value, -1) === "'")
  276. {
  277. $vals[$i] = $string . (($is_in_val) ? ', ' : '') . $value;
  278. $string = '';
  279. $is_in_val = false;
  280. if ($vals[$i][0] !== "'")
  281. {
  282. $vals[$i] = "''" . $vals[$i];
  283. }
  284. $i++;
  285. continue;
  286. }
  287. else
  288. {
  289. $string .= (($is_in_val) ? ', ' : '') . $value;
  290. $is_in_val = true;
  291. }
  292. }
  293. if ($string)
  294. {
  295. // New value if cols != value
  296. $vals[(count($cols) !== count($vals)) ? $i : $i - 1] .= $string;
  297. }
  298. $vals = array(0 => $vals);
  299. }
  300. */
  301. $inserts = $vals[0];
  302. unset($vals);
  303. foreach ($inserts as $key => $value)
  304. {
  305. if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2
  306. {
  307. $inserts[$key] = ':' . strtoupper($cols[$key]);
  308. $array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1));
  309. }
  310. }
  311. $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')';
  312. }
  313. }
  314. else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER))
  315. {
  316. if (strlen($data[0][2]) > 4000)
  317. {
  318. $update = $data[0][1];
  319. $where = $data[0][3];
  320. preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER);
  321. unset($data);
  322. $cols = array();
  323. foreach ($temp as $value)
  324. {
  325. if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2
  326. {
  327. $cols[] = $value[1] . '=:' . strtoupper($value[1]);
  328. $array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1));
  329. }
  330. else
  331. {
  332. $cols[] = $value[1] . '=' . $value[2];
  333. }
  334. }
  335. $query = $update . implode(', ', $cols) . ' ' . $where;
  336. unset($cols);
  337. }
  338. }
  339. }
  340. switch (substr($query, 0, 6))
  341. {
  342. case 'DELETE':
  343. if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs))
  344. {
  345. $query = $regs[1] . $this->_rewrite_where($regs[2]);
  346. unset($regs);
  347. }
  348. break;
  349. case 'UPDATE':
  350. if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs))
  351. {
  352. $query = $regs[1] . $this->_rewrite_where($regs[2]);
  353. unset($regs);
  354. }
  355. break;
  356. case 'SELECT':
  357. $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query);
  358. break;
  359. }
  360. $this->query_result = @ociparse($this->db_connect_id, $query);
  361. foreach ($array as $key => $value)
  362. {
  363. @ocibindbyname($this->query_result, $key, $array[$key], -1);
  364. }
  365. $success = @ociexecute($this->query_result, OCI_DEFAULT);
  366. if (!$success)
  367. {
  368. $this->sql_error($query);
  369. $this->query_result = false;
  370. }
  371. else
  372. {
  373. if (!$in_transaction)
  374. {
  375. $this->sql_transaction('commit');
  376. }
  377. }
  378. if ($this->debug_sql_explain)
  379. {
  380. $this->sql_report('stop', $query);
  381. }
  382. else if ($this->debug_load_time)
  383. {
  384. $this->sql_time += microtime(true) - $this->curtime;
  385. }
  386. if (!$this->query_result)
  387. {
  388. return false;
  389. }
  390. if ($cache && $cache_ttl)
  391. {
  392. $this->open_queries[(int) $this->query_result] = $this->query_result;
  393. $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
  394. }
  395. else if (strpos($query, 'SELECT') === 0)
  396. {
  397. $this->open_queries[(int) $this->query_result] = $this->query_result;
  398. }
  399. }
  400. else if ($this->debug_sql_explain)
  401. {
  402. $this->sql_report('fromcache', $query);
  403. }
  404. }
  405. else
  406. {
  407. return false;
  408. }
  409. return $this->query_result;
  410. }
  411. /**
  412. * Build LIMIT query
  413. */
  414. function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
  415. {
  416. $this->query_result = false;
  417. $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset;
  418. return $this->sql_query($query, $cache_ttl);
  419. }
  420. /**
  421. * {@inheritDoc}
  422. */
  423. function sql_affectedrows()
  424. {
  425. return ($this->query_result) ? @ocirowcount($this->query_result) : false;
  426. }
  427. /**
  428. * {@inheritDoc}
  429. */
  430. function sql_fetchrow($query_id = false)
  431. {
  432. global $cache;
  433. if ($query_id === false)
  434. {
  435. $query_id = $this->query_result;
  436. }
  437. if ($cache && $cache->sql_exists($query_id))
  438. {
  439. return $cache->sql_fetchrow($query_id);
  440. }
  441. if ($query_id)
  442. {
  443. $row = array();
  444. $result = ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
  445. if (!$result || !$row)
  446. {
  447. return false;
  448. }
  449. $result_row = array();
  450. foreach ($row as $key => $value)
  451. {
  452. // Oracle treats empty strings as null
  453. if (is_null($value))
  454. {
  455. $value = '';
  456. }
  457. // OCI->CLOB?
  458. if (is_object($value))
  459. {
  460. $value = $value->load();
  461. }
  462. $result_row[strtolower($key)] = $value;
  463. }
  464. return $result_row;
  465. }
  466. return false;
  467. }
  468. /**
  469. * {@inheritDoc}
  470. */
  471. function sql_rowseek($rownum, &$query_id)
  472. {
  473. global $cache;
  474. if ($query_id === false)
  475. {
  476. $query_id = $this->query_result;
  477. }
  478. if ($cache && $cache->sql_exists($query_id))
  479. {
  480. return $cache->sql_rowseek($rownum, $query_id);
  481. }
  482. if (!$query_id)
  483. {
  484. return false;
  485. }
  486. // Reset internal pointer
  487. @ociexecute($query_id, OCI_DEFAULT);
  488. // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
  489. for ($i = 0; $i < $rownum; $i++)
  490. {
  491. if (!$this->sql_fetchrow($query_id))
  492. {
  493. return false;
  494. }
  495. }
  496. return true;
  497. }
  498. /**
  499. * {@inheritDoc}
  500. */
  501. function sql_nextid()
  502. {
  503. $query_id = $this->query_result;
  504. if ($query_id !== false && $this->last_query_text != '')
  505. {
  506. if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename))
  507. {
  508. $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL';
  509. $stmt = @ociparse($this->db_connect_id, $query);
  510. if ($stmt)
  511. {
  512. $success = @ociexecute($stmt, OCI_DEFAULT);
  513. if ($success)
  514. {
  515. $temp_result = ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS);
  516. ocifreestatement($stmt);
  517. if ($temp_result)
  518. {
  519. return $temp_array['CURRVAL'];
  520. }
  521. else
  522. {
  523. return false;
  524. }
  525. }
  526. }
  527. }
  528. }
  529. return false;
  530. }
  531. /**
  532. * {@inheritDoc}
  533. */
  534. function sql_freeresult($query_id = false)
  535. {
  536. global $cache;
  537. if ($query_id === false)
  538. {
  539. $query_id = $this->query_result;
  540. }
  541. if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
  542. {
  543. return $cache->sql_freeresult($query_id);
  544. }
  545. if (isset($this->open_queries[(int) $query_id]))
  546. {
  547. unset($this->open_queries[(int) $query_id]);
  548. return ocifreestatement($query_id);
  549. }
  550. return false;
  551. }
  552. /**
  553. * {@inheritDoc}
  554. */
  555. function sql_escape($msg)
  556. {
  557. return str_replace(array("'", "\0"), array("''", ''), $msg);
  558. }
  559. /**
  560. * Build LIKE expression
  561. * @access private
  562. */
  563. function _sql_like_expression($expression)
  564. {
  565. return $expression . " ESCAPE '\\'";
  566. }
  567. /**
  568. * Build NOT LIKE expression
  569. * @access private
  570. */
  571. function _sql_not_like_expression($expression)
  572. {
  573. return $expression . " ESCAPE '\\'";
  574. }
  575. function _sql_custom_build($stage, $data)
  576. {
  577. return $data;
  578. }
  579. function _sql_bit_and($column_name, $bit, $compare = '')
  580. {
  581. return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
  582. }
  583. function _sql_bit_or($column_name, $bit, $compare = '')
  584. {
  585. return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
  586. }
  587. /**
  588. * return sql error array
  589. * @access private
  590. */
  591. function _sql_error()
  592. {
  593. if (function_exists('ocierror'))
  594. {
  595. $error = @ocierror();
  596. $error = (!$error) ? @ocierror($this->query_result) : $error;
  597. $error = (!$error) ? @ocierror($this->db_connect_id) : $error;
  598. if ($error)
  599. {
  600. $this->last_error_result = $error;
  601. }
  602. else
  603. {
  604. $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array();
  605. }
  606. }
  607. else
  608. {
  609. $error = array(
  610. 'message' => $this->connect_error,
  611. 'code' => '',
  612. );
  613. }
  614. return $error;
  615. }
  616. /**
  617. * Close sql connection
  618. * @access private
  619. */
  620. function _sql_close()
  621. {
  622. return @ocilogoff($this->db_connect_id);
  623. }
  624. /**
  625. * Build db-specific report
  626. * @access private
  627. */
  628. function _sql_report($mode, $query = '')
  629. {
  630. switch ($mode)
  631. {
  632. case 'start':
  633. $html_table = false;
  634. // Grab a plan table, any will do
  635. $sql = "SELECT table_name
  636. FROM USER_TABLES
  637. WHERE table_name LIKE '%PLAN_TABLE%'";
  638. $stmt = ociparse($this->db_connect_id, $sql);
  639. ociexecute($stmt);
  640. $result = array();
  641. if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS))
  642. {
  643. $table = $result['TABLE_NAME'];
  644. // This is the statement_id that will allow us to track the plan
  645. $statement_id = substr(md5($query), 0, 30);
  646. // Remove any stale plans
  647. $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
  648. ociexecute($stmt2);
  649. ocifreestatement($stmt2);
  650. // Explain the plan
  651. $sql = "EXPLAIN PLAN
  652. SET STATEMENT_ID = '$statement_id'
  653. FOR $query";
  654. $stmt2 = ociparse($this->db_connect_id, $sql);
  655. ociexecute($stmt2);
  656. ocifreestatement($stmt2);
  657. // Get the data from the plan
  658. $sql = "SELECT operation, options, object_name, object_type, cardinality, cost
  659. FROM plan_table
  660. START WITH id = 0 AND statement_id = '$statement_id'
  661. CONNECT BY PRIOR id = parent_id
  662. AND statement_id = '$statement_id'";
  663. $stmt2 = ociparse($this->db_connect_id, $sql);
  664. ociexecute($stmt2);
  665. $row = array();
  666. while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS))
  667. {
  668. $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
  669. }
  670. ocifreestatement($stmt2);
  671. // Remove the plan we just made, we delete them on request anyway
  672. $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
  673. ociexecute($stmt2);
  674. ocifreestatement($stmt2);
  675. }
  676. ocifreestatement($stmt);
  677. if ($html_table)
  678. {
  679. $this->html_hold .= '</table>';
  680. }
  681. break;
  682. case 'fromcache':
  683. $endtime = explode(' ', microtime());
  684. $endtime = $endtime[0] + $endtime[1];
  685. $result = @ociparse($this->db_connect_id, $query);
  686. if ($result)
  687. {
  688. $success = @ociexecute($result, OCI_DEFAULT);
  689. if ($success)
  690. {
  691. $row = array();
  692. while (ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS))
  693. {
  694. // Take the time spent on parsing rows into account
  695. }
  696. @ocifreestatement($result);
  697. }
  698. }
  699. $splittime = explode(' ', microtime());
  700. $splittime = $splittime[0] + $splittime[1];
  701. $this->sql_report('record_fromcache', $query, $endtime, $splittime);
  702. break;
  703. }
  704. }
  705. }