Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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