Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

oracle.php

Zuletzt modifiziert: 02.04.2025, 15:02 - Dateigröße: 19.32 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  namespace phpbb\db\driver;
015   
016  /**
017  * Oracle Database Abstraction Layer
018  */
019  class oracle extends \phpbb\db\driver\driver
020  {
021      var $last_query_text = '';
022      var $connect_error = '';
023   
024      /**
025      * {@inheritDoc}
026      */
027      function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
028      {
029          $this->persistency = $persistency;
030          $this->user = $sqluser;
031          $this->server = $sqlserver . (($port) ? ':' . $port : '');
032          $this->dbname = $database;
033   
034          $connect = $database;
035   
036          // support for "easy connect naming"
037          if ($sqlserver !== '' && $sqlserver !== '/')
038          {
039              if (substr($sqlserver, -1, 1) == '/')
040              {
041                  $sqlserver == substr($sqlserver, 0, -1);
042              }
043              $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database;
044          }
045   
046          if ($new_link)
047          {
048              if (!function_exists('oci_new_connect'))
049              {
050                  $this->connect_error = 'oci_new_connect function does not exist, is oci extension installed?';
051                  return $this->sql_error('');
052              }
053              $this->db_connect_id = @oci_new_connect($this->user, $sqlpassword, $connect, 'UTF8');
054          }
055          else if ($this->persistency)
056          {
057              if (!function_exists('oci_pconnect'))
058              {
059                  $this->connect_error = 'oci_pconnect function does not exist, is oci extension installed?';
060                  return $this->sql_error('');
061              }
062              $this->db_connect_id = @oci_pconnect($this->user, $sqlpassword, $connect, 'UTF8');
063          }
064          else
065          {
066              if (!function_exists('oci_connect'))
067              {
068                  $this->connect_error = 'oci_connect function does not exist, is oci extension installed?';
069                  return $this->sql_error('');
070              }
071              $this->db_connect_id = @oci_connect($this->user, $sqlpassword, $connect, 'UTF8');
072          }
073   
074          return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
075      }
076   
077      /**
078      * {@inheritDoc}
079      */
080      function sql_server_info($raw = false, $use_cache = true)
081      {
082          /**
083          * force $use_cache false.  I didn't research why the caching code below is commented out
084          * but I assume its because the Oracle extension provides a direct method to access it
085          * without a query.
086          */
087  /*
088          global $cache;
089   
090          if (empty($cache) || ($this->sql_server_version = $cache->get('oracle_version')) === false)
091          {
092              $result = @ociparse($this->db_connect_id, 'SELECT * FROM v$version WHERE banner LIKE \'Oracle%\'');
093              @ociexecute($result, OCI_DEFAULT);
094              @ocicommit($this->db_connect_id);
095   
096              $row = array();
097              @ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS);
098              @ocifreestatement($result);
099              $this->sql_server_version = trim($row['BANNER']);
100   
101              $cache->put('oracle_version', $this->sql_server_version);
102          }
103  */
104          $this->sql_server_version = @oci_server_version($this->db_connect_id);
105   
106          return $this->sql_server_version;
107      }
108   
109      /**
110      * SQL Transaction
111      * @access private
112      */
113      function _sql_transaction($status = 'begin')
114      {
115          switch ($status)
116          {
117              case 'begin':
118                  return true;
119              break;
120   
121              case 'commit':
122                  return @oci_commit($this->db_connect_id);
123              break;
124   
125              case 'rollback':
126                  return @oci_rollback($this->db_connect_id);
127              break;
128          }
129   
130          return true;
131      }
132   
133      /**
134      * Oracle specific code to handle the fact that it does not compare columns properly
135      * @access private
136      */
137      function _rewrite_col_compare($args)
138      {
139          if (count($args) == 4)
140          {
141              if ($args[2] == '=')
142              {
143                  return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))';
144              }
145              else if ($args[2] == '<>')
146              {
147                  // really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P
148                  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)))';
149              }
150          }
151          else
152          {
153              return $this->_rewrite_where($args[0]);
154          }
155      }
156   
157      /**
158      * Oracle specific code to handle it's lack of sanity
159      * @access private
160      */
161      function _rewrite_where($where_clause)
162      {
163          preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER);
164          $out = '';
165          foreach ($result as $val)
166          {
167              if (!isset($val[5]))
168              {
169                  if ($val[4] !== "''")
170                  {
171                      $out .= $val[0];
172                  }
173                  else
174                  {
175                      $out .= ' ' . $val[1] . ' ' . $val[2];
176                      if ($val[3] == '=')
177                      {
178                          $out .= ' is NULL';
179                      }
180                      else if ($val[3] == '<>')
181                      {
182                          $out .= ' is NOT NULL';
183                      }
184                  }
185              }
186              else
187              {
188                  $in_clause = array();
189                  $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1);
190                  $extra = false;
191                  preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER);
192                  $i = 0;
193                  foreach ($sub_vals[0] as $sub_val)
194                  {
195                      // two things:
196                      // 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison
197                      // 2) This fixes the 1000 list limit that Oracle has (ORA-01795)
198                      if ($sub_val !== "''")
199                      {
200                          $in_clause[(int) $i++/1000][] = $sub_val;
201                      }
202                      else
203                      {
204                          $extra = true;
205                      }
206                  }
207                  if (!$extra && $i < 1000)
208                  {
209                      $out .= $val[0];
210                  }
211                  else
212                  {
213                      $out .= ' ' . $val[1] . '(';
214                      $in_array = array();
215   
216                      // constuct each IN() clause
217                      foreach ($in_clause as $in_values)
218                      {
219                          $in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')';
220                      }
221   
222                      // Join the IN() clauses against a few ORs (IN is just a nicer OR anyway)
223                      $out .= implode(' OR ', $in_array);
224   
225                      // handle the empty string case
226                      if ($extra)
227                      {
228                          $out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL';
229                      }
230                      $out .= ')';
231   
232                      unset($in_array, $in_clause);
233                  }
234              }
235          }
236   
237          return $out;
238      }
239   
240      /**
241      * {@inheritDoc}
242      */
243      function sql_query($query = '', $cache_ttl = 0)
244      {
245          if ($query != '')
246          {
247              global $cache;
248   
249              if ($this->debug_sql_explain)
250              {
251                  $this->sql_report('start', $query);
252              }
253              else if ($this->debug_load_time)
254              {
255                  $this->curtime = microtime(true);
256              }
257   
258              $this->last_query_text = $query;
259              $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
260              $this->sql_add_num_queries($this->query_result);
261   
262              if ($this->query_result === false)
263              {
264                  $in_transaction = false;
265                  if (!$this->transaction)
266                  {
267                      $this->sql_transaction('begin');
268                  }
269                  else
270                  {
271                      $in_transaction = true;
272                  }
273   
274                  $array = array();
275   
276                  // We overcome Oracle's 4000 char limit by binding vars
277                  if (strlen($query) > 4000)
278                  {
279                      if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/sU', $query, $regs))
280                      {
281                          if (strlen($regs[3]) > 4000)
282                          {
283                              $cols = explode(', ', $regs[2]);
284   
285                              preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER);
286   
287  /*                        The code inside this comment block breaks clob handling, but does allow the
288                          database restore script to work.  If you want to allow no posts longer than 4KB
289                          and/or need the db restore script, uncomment this.
290   
291   
292                              if (count($cols) !== count($vals))
293                              {
294                                  // Try to replace some common data we know is from our restore script or from other sources
295                                  $regs[3] = str_replace("'||chr(47)||'", '/', $regs[3]);
296                                  $_vals = explode(', ', $regs[3]);
297   
298                                  $vals = array();
299                                  $is_in_val = false;
300                                  $i = 0;
301                                  $string = '';
302   
303                                  foreach ($_vals as $value)
304                                  {
305                                      if (strpos($value, "'") === false && !$is_in_val)
306                                      {
307                                          $vals[$i++] = $value;
308                                          continue;
309                                      }
310   
311                                      if (substr($value, -1) === "'")
312                                      {
313                                          $vals[$i] = $string . (($is_in_val) ? ', ' : '') . $value;
314                                          $string = '';
315                                          $is_in_val = false;
316   
317                                          if ($vals[$i][0] !== "'")
318                                          {
319                                              $vals[$i] = "''" . $vals[$i];
320                                          }
321                                          $i++;
322                                          continue;
323                                      }
324                                      else
325                                      {
326                                          $string .= (($is_in_val) ? ', ' : '') . $value;
327                                          $is_in_val = true;
328                                      }
329                                  }
330   
331                                  if ($string)
332                                  {
333                                      // New value if cols != value
334                                      $vals[(count($cols) !== count($vals)) ? $i : $i - 1] .= $string;
335                                  }
336   
337                                  $vals = array(0 => $vals);
338                              }
339  */
340   
341                              $inserts = $vals[0];
342                              unset($vals);
343   
344                              foreach ($inserts as $key => $value)
345                              {
346                                  if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2
347                                  {
348                                      $inserts[$key] = ':' . strtoupper($cols[$key]);
349                                      $array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1));
350                                  }
351                              }
352   
353                              $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')';
354                          }
355                      }
356                      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))
357                      {
358                          if (strlen($data[0][2]) > 4000)
359                          {
360                              $update = $data[0][1];
361                              $where = $data[0][3];
362                              preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER);
363                              unset($data);
364   
365                              $cols = array();
366                              foreach ($temp as $value)
367                              {
368                                  if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2
369                                  {
370                                      $cols[] = $value[1] . '=:' . strtoupper($value[1]);
371                                      $array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1));
372                                  }
373                                  else
374                                  {
375                                      $cols[] = $value[1] . '=' . $value[2];
376                                  }
377                              }
378   
379                              $query = $update . implode(', ', $cols) . ' ' . $where;
380                              unset($cols);
381                          }
382                      }
383                  }
384   
385                  switch (substr($query, 0, 6))
386                  {
387                      case 'DELETE':
388                          if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs))
389                          {
390                              $query = $regs[1] . $this->_rewrite_where($regs[2]);
391                              unset($regs);
392                          }
393                      break;
394   
395                      case 'UPDATE':
396                          if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s',  $query, $regs))
397                          {
398                              $query = $regs[1] . $this->_rewrite_where($regs[2]);
399                              unset($regs);
400                          }
401                      break;
402   
403                      case 'SELECT':
404                          $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query);
405                      break;
406                  }
407   
408                  $this->query_result = @oci_parse($this->db_connect_id, $query);
409   
410                  foreach ($array as $key => $value)
411                  {
412                      @oci_bind_by_name($this->query_result, $key, $array[$key], -1);
413                  }
414   
415                  $success = @oci_execute($this->query_result, OCI_DEFAULT);
416   
417                  if (!$success)
418                  {
419                      $this->sql_error($query);
420                      $this->query_result = false;
421                  }
422                  else
423                  {
424                      if (!$in_transaction)
425                      {
426                          $this->sql_transaction('commit');
427                      }
428                  }
429   
430                  if ($this->debug_sql_explain)
431                  {
432                      $this->sql_report('stop', $query);
433                  }
434                  else if ($this->debug_load_time)
435                  {
436                      $this->sql_time += microtime(true) - $this->curtime;
437                  }
438   
439                  if (!$this->query_result)
440                  {
441                      return false;
442                  }
443   
444                  $safe_query_id = $this->clean_query_id($this->query_result);
445   
446                  if ($cache && $cache_ttl)
447                  {
448                      $this->open_queries[$safe_query_id] = $this->query_result;
449                      $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
450                  }
451                  else if (strpos($query, 'SELECT') === 0)
452                  {
453                      $this->open_queries[$safe_query_id] = $this->query_result;
454                  }
455              }
456              else if ($this->debug_sql_explain)
457              {
458                  $this->sql_report('fromcache', $query);
459              }
460          }
461          else
462          {
463              return false;
464          }
465   
466          return $this->query_result;
467      }
468   
469      /**
470      * Build LIMIT query
471      */
472      function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
473      {
474          $this->query_result = false;
475   
476          $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset;
477   
478          return $this->sql_query($query, $cache_ttl);
479      }
480   
481      /**
482      * {@inheritDoc}
483      */
484      function sql_affectedrows()
485      {
486          return ($this->query_result) ? @oci_num_rows($this->query_result) : false;
487      }
488   
489      /**
490      * {@inheritDoc}
491      */
492      function sql_fetchrow($query_id = false)
493      {
494          global $cache;
495   
496          if ($query_id === false)
497          {
498              $query_id = $this->query_result;
499          }
500   
501          $safe_query_id = $this->clean_query_id($query_id);
502          if ($cache && $cache->sql_exists($safe_query_id))
503          {
504              return $cache->sql_fetchrow($safe_query_id);
505          }
506   
507          if ($query_id)
508          {
509              if (!$row = oci_fetch_array($query_id, OCI_ASSOC + OCI_RETURN_NULLS))
510              {
511                  return false;
512              }
513   
514              $result_row = array();
515              foreach ($row as $key => $value)
516              {
517                  // Oracle treats empty strings as null
518                  if (is_null($value))
519                  {
520                      $value = '';
521                  }
522   
523                  // OCI->CLOB?
524                  if (is_object($value))
525                  {
526                      $value = $value->load();
527                  }
528   
529                  $result_row[strtolower($key)] = $value;
530              }
531   
532              return $result_row;
533          }
534   
535          return false;
536      }
537   
538      /**
539      * {@inheritDoc}
540      */
541      function sql_rowseek($rownum, &$query_id)
542      {
543          global $cache;
544   
545          if ($query_id === false)
546          {
547              $query_id = $this->query_result;
548          }
549   
550          $safe_query_id = $this->clean_query_id($query_id);
551          if ($cache && $cache->sql_exists($safe_query_id))
552          {
553              return $cache->sql_rowseek($rownum, $safe_query_id);
554          }
555   
556          if (!$query_id)
557          {
558              return false;
559          }
560   
561          // Reset internal pointer
562          @oci_execute($query_id, OCI_DEFAULT);
563   
564          // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
565          for ($i = 0; $i < $rownum; $i++)
566          {
567              if (!$this->sql_fetchrow($query_id))
568              {
569                  return false;
570              }
571          }
572   
573          return true;
574      }
575   
576      /**
577       * {@inheritdoc}
578       */
579      public function sql_last_inserted_id()
580      {
581          $query_id = $this->query_result;
582   
583          if ($query_id !== false && $this->last_query_text != '')
584          {
585              if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename))
586              {
587                  $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL';
588                  $stmt = @oci_parse($this->db_connect_id, $query);
589                  if ($stmt)
590                  {
591                      $success = @oci_execute($stmt, OCI_DEFAULT);
592   
593                      if ($success)
594                      {
595                          $temp_array = oci_fetch_array($stmt, OCI_ASSOC + OCI_RETURN_NULLS);
596                          oci_free_statement($stmt);
597   
598                          if (!empty($temp_array))
599                          {
600                              return $temp_array['CURRVAL'];
601                          }
602                          else
603                          {
604                              return false;
605                          }
606                      }
607                  }
608              }
609          }
610   
611          return false;
612      }
613   
614      /**
615      * {@inheritDoc}
616      */
617      function sql_freeresult($query_id = false)
618      {
619          global $cache;
620   
621          if ($query_id === false)
622          {
623              $query_id = $this->query_result;
624          }
625   
626          $safe_query_id = $this->clean_query_id($query_id);
627          if ($cache && $cache->sql_exists($safe_query_id))
628          {
629              return $cache->sql_freeresult($safe_query_id);
630          }
631   
632          if (isset($this->open_queries[$safe_query_id]))
633          {
634              unset($this->open_queries[$safe_query_id]);
635              return oci_free_statement($query_id);
636          }
637   
638          return false;
639      }
640   
641      /**
642      * {@inheritDoc}
643      */
644      function sql_escape($msg)
645      {
646          return str_replace(array("'", "\0"), array("''", ''), $msg);
647      }
648   
649      /**
650      * Build LIKE expression
651      * @access private
652      */
653      function _sql_like_expression($expression)
654      {
655          return $expression . " ESCAPE '\\'";
656      }
657   
658      /**
659      * Build NOT LIKE expression
660      * @access private
661      */
662      function _sql_not_like_expression($expression)
663      {
664          return $expression . " ESCAPE '\\'";
665      }
666   
667      function _sql_custom_build($stage, $data)
668      {
669          return $data;
670      }
671   
672      function _sql_bit_and($column_name, $bit, $compare = '')
673      {
674          return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
675      }
676   
677      function _sql_bit_or($column_name, $bit, $compare = '')
678      {
679          return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
680      }
681   
682      /**
683      * return sql error array
684      * @access private
685      */
686      function _sql_error()
687      {
688          if (function_exists('oci_error'))
689          {
690              $error = @oci_error();
691              $error = (!$error) ? @oci_error($this->query_result) : $error;
692              $error = (!$error) ? @oci_error($this->db_connect_id) : $error;
693   
694              if ($error)
695              {
696                  $this->last_error_result = $error;
697              }
698              else
699              {
700                  $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array();
701              }
702          }
703          else
704          {
705              $error = array(
706                  'message'    => $this->connect_error,
707                  'code'        => '',
708              );
709          }
710   
711          return $error;
712      }
713   
714      /**
715      * Close sql connection
716      * @access private
717      */
718      function _sql_close()
719      {
720          return @oci_close($this->db_connect_id);
721      }
722   
723      /**
724      * Build db-specific report
725      * @access private
726      */
727      function _sql_report($mode, $query = '')
728      {
729          switch ($mode)
730          {
731              case 'start':
732   
733                  $html_table = false;
734   
735                  // Grab a plan table, any will do
736                  $sql = "SELECT table_name
737                      FROM USER_TABLES
738                      WHERE table_name LIKE '%PLAN_TABLE%'";
739                  $stmt = oci_parse($this->db_connect_id, $sql);
740                  oci_execute($stmt);
741   
742                  if ($result = oci_fetch_array($stmt, OCI_ASSOC + OCI_RETURN_NULLS))
743                  {
744                      $table = $result['TABLE_NAME'];
745   
746                      // This is the statement_id that will allow us to track the plan
747                      $statement_id = substr(md5($query), 0, 30);
748   
749                      // Remove any stale plans
750                      $stmt2 = oci_parse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
751                      oci_execute($stmt2);
752                      oci_free_statement($stmt2);
753   
754                      // Explain the plan
755                      $sql = "EXPLAIN PLAN
756                          SET STATEMENT_ID = '$statement_id'
757                          FOR $query";
758                      $stmt2 = oci_parse($this->db_connect_id, $sql);
759                      oci_execute($stmt2);
760                      oci_free_statement($stmt2);
761   
762                      // Get the data from the plan
763                      $sql = "SELECT operation, options, object_name, object_type, cardinality, cost
764                          FROM plan_table
765                          START WITH id = 0 AND statement_id = '$statement_id'
766                          CONNECT BY PRIOR id = parent_id
767                              AND statement_id = '$statement_id'";
768                      $stmt2 = oci_parse($this->db_connect_id, $sql);
769                      oci_execute($stmt2);
770   
771                      while ($row = oci_fetch_array($stmt2, OCI_ASSOC + OCI_RETURN_NULLS))
772                      {
773                          $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
774                      }
775   
776                      oci_free_statement($stmt2);
777   
778                      // Remove the plan we just made, we delete them on request anyway
779                      $stmt2 = oci_parse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
780                      oci_execute($stmt2);
781                      oci_free_statement($stmt2);
782                  }
783   
784                  oci_free_statement($stmt);
785   
786                  if ($html_table)
787                  {
788                      $this->html_hold .= '</table>';
789                  }
790   
791              break;
792   
793              case 'fromcache':
794                  $endtime = explode(' ', microtime());
795                  $endtime = $endtime[0] + $endtime[1];
796   
797                  $result = @oci_parse($this->db_connect_id, $query);
798                  if ($result)
799                  {
800                      $success = @oci_execute($result, OCI_DEFAULT);
801                      if ($success)
802                      {
803                          array();
804   
805                          while ($row = oci_fetch_array($result, OCI_ASSOC + OCI_RETURN_NULLS))
806                          {
807                              // Take the time spent on parsing rows into account
808                          }
809                          @oci_free_statement($result);
810                      }
811                  }
812   
813                  $splittime = explode(' ', microtime());
814                  $splittime = $splittime[0] + $splittime[1];
815   
816                  $this->sql_report('record_fromcache', $query, $endtime, $splittime);
817   
818              break;
819          }
820      }
821   
822      /**
823      * {@inheritDoc}
824      */
825      function sql_quote($msg)
826      {
827          return '"' . $msg . '"';
828      }
829  }
830