Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

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:51 - Dateigröße: 15.67 KiB


001  <?php
002  /**
003  *
004  * @package dbal
005  * @version $Id$
006  * @copyright (c) 2005 phpBB Group
007  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
008  *
009  */
010   
011  /**
012  * @ignore
013  */
014  if (!defined('IN_PHPBB'))
015  {
016      exit;
017  }
018   
019  include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
020   
021  /**
022  * Oracle Database Abstraction Layer
023  * @package dbal
024  */
025  class dbal_oracle extends dbal
026  {
027      var $last_query_text = '';
028   
029      /**
030      * Connect to server
031      */
032      function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
033      {
034          $this->persistency = $persistency;
035          $this->user = $sqluser;
036          $this->server = $sqlserver . (($port) ? ':' . $port : '');
037          $this->dbname = $database;
038   
039          $connect = $database;
040   
041          // support for "easy connect naming"
042          if ($sqlserver !== '' && $sqlserver !== '/')
043          {
044              if (substr($sqlserver, -1, 1) == '/')
045              {
046                  $sqlserver == substr($sqlserver, 0, -1);
047              }
048              $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database;
049          }
050   
051          $this->db_connect_id = ($new_link) ? @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8') : (($this->persistency) ? @ociplogon($this->user, $sqlpassword, $connect, 'UTF8') : @ocilogon($this->user, $sqlpassword, $connect, 'UTF8'));
052   
053          return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
054      }
055   
056      /**
057      * Version information about used database
058      */
059      function sql_server_info()
060      {
061          return @ociserverversion($this->db_connect_id);
062      }
063   
064      /**
065      * SQL Transaction
066      * @access private
067      */
068      function _sql_transaction($status = 'begin')
069      {
070          switch ($status)
071          {
072              case 'begin':
073                  return true;
074              break;
075   
076              case 'commit':
077                  return @ocicommit($this->db_connect_id);
078              break;
079   
080              case 'rollback':
081                  return @ocirollback($this->db_connect_id);
082              break;
083          }
084   
085          return true;
086      }
087   
088      /**
089      * Oracle specific code to handle the fact that it does not compare columns properly
090      * @access private
091      */
092      function _rewrite_col_compare($args)
093      {
094          if (sizeof($args) == 4)
095          {
096              if ($args[2] == '=')
097              {
098                  return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))';
099              }
100              else if ($args[2] == '<>')
101              {
102                  // really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P
103                  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)))';
104              }
105          }
106          else
107          {
108              return $this->_rewrite_where($args[0]);
109          }
110      }
111   
112      /**
113      * Oracle specific code to handle it's lack of sanity
114      * @access private
115      */
116      function _rewrite_where($where_clause)
117      {
118          preg_match_all('/\s*(AND|OR)?\s*([\w_.]++)\s*(?:(=|<[=>]?|>=?)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER);
119          $out = '';
120          foreach ($result as $val)
121          {
122              if (!isset($val[5]))
123              {
124                  if ($val[4] !== "''")
125                  {
126                      $out .= $val[0];
127                  }
128                  else
129                  {
130                      $out .= ' ' . $val[1] . ' ' . $val[2];
131                      if ($val[3] == '=')
132                      {
133                          $out .= ' is NULL';
134                      }
135                      else if ($val[3] == '<>')
136                      {
137                          $out .= ' is NOT NULL';
138                      }
139                  }
140              }
141              else
142              {
143                  $in_clause = array();
144                  $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1);
145                  $extra = false;
146                  preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER);
147                  $i = 0;
148                  foreach ($sub_vals[0] as $sub_val)
149                  {
150                      // two things:
151                      // 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison
152                      // 2) This fixes the 1000 list limit that Oracle has (ORA-01795)
153                      if ($sub_val !== "''")
154                      {
155                          $in_clause[(int) $i++/1000][] = $sub_val;
156                      }
157                      else
158                      {
159                          $extra = true;
160                      }
161                  }
162                  if (!$extra && $i < 1000)
163                  {
164                      $out .= $val[0];
165                  }
166                  else
167                  {
168                      $out .= ' ' . $val[1] . '(';
169                      $in_array = array();
170   
171                      // constuct each IN() clause    
172                      foreach ($in_clause as $in_values)
173                      {
174                          $in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')';
175                      }
176   
177                      // Join the IN() clauses against a few ORs (IN is just a nicer OR anyway)
178                      $out .= implode(' OR ', $in_array);
179   
180                      // handle the empty string case
181                      if ($extra)
182                      {
183                          $out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL';
184                      }
185                      $out .= ')';
186   
187                      unset($in_array, $in_clause);
188                  }
189              }
190          }
191   
192          return $out;
193      }
194   
195      /**
196      * Base query method
197      *
198      * @param    string    $query        Contains the SQL query which shall be executed
199      * @param    int        $cache_ttl    Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
200      * @return    mixed                When casted to bool the returned value returns true on success and false on failure
201      *
202      * @access    public
203      */
204      function sql_query($query = '', $cache_ttl = 0)
205      {
206          if ($query != '')
207          {
208              global $cache;
209   
210              // EXPLAIN only in extra debug mode
211              if (defined('DEBUG_EXTRA'))
212              {
213                  $this->sql_report('start', $query);
214              }
215   
216              $this->last_query_text = $query;
217              $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false;
218              $this->sql_add_num_queries($this->query_result);
219   
220              if ($this->query_result === false)
221              {
222                  $in_transaction = false;
223                  if (!$this->transaction)
224                  {
225                      $this->sql_transaction('begin');
226                  }
227                  else
228                  {
229                      $in_transaction = true;
230                  }
231   
232                  $array = array();
233   
234                  // We overcome Oracle's 4000 char limit by binding vars
235                  if (strlen($query) > 4000)
236                  {
237                      if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/s', $query, $regs))
238                      {
239                          if (strlen($regs[3]) > 4000)
240                          {
241                              $cols = explode(', ', $regs[2]);
242                              preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER);
243   
244                              $inserts = $vals[0];
245                              unset($vals);
246   
247                              foreach ($inserts as $key => $value)
248                              {
249                                  if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2
250                                  {
251                                      $inserts[$key] = ':' . strtoupper($cols[$key]);
252                                      $array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1));
253                                  }
254                              }
255   
256                              $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')';
257                          }
258                      }
259                      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))
260                      {
261                          if (strlen($data[0][2]) > 4000)
262                          {
263                              $update = $data[0][1];
264                              $where = $data[0][3];
265                              preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER);
266                              unset($data);
267   
268                              $cols = array();
269                              foreach ($temp as $value)
270                              {
271                                  if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2
272                                  {
273                                      $cols[] = $value[1] . '=:' . strtoupper($value[1]);
274                                      $array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1));
275                                  }
276                                  else
277                                  {
278                                      $cols[] = $value[1] . '=' . $value[2];
279                                  }
280                              }
281   
282                              $query = $update . implode(', ', $cols) . ' ' . $where;
283                              unset($cols);
284                          }
285                      }
286                  }
287   
288                  switch (substr($query, 0, 6))
289                  {
290                      case 'DELETE':
291                          if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs))
292                          {
293                              $query = $regs[1] . $this->_rewrite_where($regs[2]);
294                              unset($regs);
295                          }
296                      break;
297   
298                      case 'UPDATE':
299                          if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s',  $query, $regs))
300                          {
301                              $query = $regs[1] . $this->_rewrite_where($regs[2]);
302                              unset($regs);
303                          }
304                      break;
305   
306                      case 'SELECT':
307                          $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query);
308                      break;
309                  }
310   
311                  $this->query_result = @ociparse($this->db_connect_id, $query);
312   
313                  foreach ($array as $key => $value)
314                  {
315                      @ocibindbyname($this->query_result, $key, $array[$key], -1);
316                  }
317   
318                  $success = @ociexecute($this->query_result, OCI_DEFAULT);
319   
320                  if (!$success)
321                  {
322                      $this->sql_error($query);
323                      $this->query_result = false;
324                  }
325                  else
326                  {
327                      if (!$in_transaction)
328                      {
329                          $this->sql_transaction('commit');
330                      }
331                  }
332   
333                  if (defined('DEBUG_EXTRA'))
334                  {
335                      $this->sql_report('stop', $query);
336                  }
337   
338                  if ($cache_ttl && method_exists($cache, 'sql_save'))
339                  {
340                      $this->open_queries[(int) $this->query_result] = $this->query_result;
341                      $cache->sql_save($query, $this->query_result, $cache_ttl);
342                  }
343                  else if (strpos($query, 'SELECT') === 0 && $this->query_result)
344                  {
345                      $this->open_queries[(int) $this->query_result] = $this->query_result;
346                  }
347              }
348              else if (defined('DEBUG_EXTRA'))
349              {
350                  $this->sql_report('fromcache', $query);
351              }
352          }
353          else
354          {
355              return false;
356          }
357   
358          return ($this->query_result) ? $this->query_result : false;
359      }
360   
361      /**
362      * Build LIMIT query
363      */
364      function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
365      {
366          $this->query_result = false;
367   
368          $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset;
369   
370          return $this->sql_query($query, $cache_ttl);
371      }
372   
373      /**
374      * Return number of affected rows
375      */
376      function sql_affectedrows()
377      {
378          return ($this->query_result) ? @ocirowcount($this->query_result) : false;
379      }
380   
381      /**
382      * Fetch current row
383      */
384      function sql_fetchrow($query_id = false)
385      {
386          global $cache;
387   
388          if ($query_id === false)
389          {
390              $query_id = $this->query_result;
391          }
392   
393          if (isset($cache->sql_rowset[$query_id]))
394          {
395              return $cache->sql_fetchrow($query_id);
396          }
397   
398          if ($query_id !== false)
399          {
400              $row = array();
401              $result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
402   
403              if (!$result || !$row)
404              {
405                  return false;
406              }
407   
408              $result_row = array();
409              foreach ($row as $key => $value)
410              {
411                  // Oracle treats empty strings as null
412                  if (is_null($value))
413                  {
414                      $value = '';
415                  }
416   
417                  // OCI->CLOB?
418                  if (is_object($value))
419                  {
420                      $value = $value->load();
421                  }
422   
423                  $result_row[strtolower($key)] = $value;
424              }
425   
426              return $result_row;
427          }
428   
429          return false;
430      }
431   
432      /**
433      * Seek to given row number
434      * rownum is zero-based
435      */
436      function sql_rowseek($rownum, &$query_id)
437      {
438          global $cache;
439   
440          if ($query_id === false)
441          {
442              $query_id = $this->query_result;
443          }
444   
445          if (isset($cache->sql_rowset[$query_id]))
446          {
447              return $cache->sql_rowseek($rownum, $query_id);
448          }
449   
450          if ($query_id === false)
451          {
452              return false;
453          }
454   
455          // Reset internal pointer
456          @ociexecute($query_id, OCI_DEFAULT);
457   
458          // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
459          for ($i = 0; $i < $rownum; $i++)
460          {
461              if (!$this->sql_fetchrow($query_id))
462              {
463                  return false;
464              }
465          }
466   
467          return true;
468      }
469   
470      /**
471      * Get last inserted id after insert statement
472      */
473      function sql_nextid()
474      {
475          $query_id = $this->query_result;
476   
477          if ($query_id !== false && $this->last_query_text != '')
478          {
479              if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename))
480              {
481                  $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL';
482                  $stmt = @ociparse($this->db_connect_id, $query);
483                  @ociexecute($stmt, OCI_DEFAULT);
484   
485                  $temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS);
486                  @ocifreestatement($stmt);
487   
488                  if ($temp_result)
489                  {
490                      return $temp_array['CURRVAL'];
491                  }
492                  else
493                  {
494                      return false;
495                  }
496              }
497          }
498   
499          return false;
500      }
501   
502      /**
503      * Free sql result
504      */
505      function sql_freeresult($query_id = false)
506      {
507          global $cache;
508   
509          if ($query_id === false)
510          {
511              $query_id = $this->query_result;
512          }
513   
514          if (isset($cache->sql_rowset[$query_id]))
515          {
516              return $cache->sql_freeresult($query_id);
517          }
518   
519          if (isset($this->open_queries[(int) $query_id]))
520          {
521              unset($this->open_queries[(int) $query_id]);
522              return @ocifreestatement($query_id);
523          }
524   
525          return false;
526      }
527   
528      /**
529      * Escape string used in sql query
530      */
531      function sql_escape($msg)
532      {
533          return str_replace("'", "''", $msg);
534      }
535   
536      /**
537      * Build LIKE expression
538      * @access private
539      */
540      function _sql_like_expression($expression)
541      {
542          return $expression . " ESCAPE '\\'";
543      }
544   
545      function _sql_custom_build($stage, $data)
546      {
547          return $data;
548      }
549   
550      /**
551      * return sql error array
552      * @access private
553      */
554      function _sql_error()
555      {
556          $error = @ocierror();
557          $error = (!$error) ? @ocierror($this->query_result) : $error;
558          $error = (!$error) ? @ocierror($this->db_connect_id) : $error;
559   
560          if ($error)
561          {
562              $this->last_error_result = $error;
563          }
564          else
565          {
566              $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array();
567          }
568   
569          return $error;
570      }
571   
572      /**
573      * Close sql connection
574      * @access private
575      */
576      function _sql_close()
577      {
578          return @ocilogoff($this->db_connect_id);
579      }
580   
581      /**
582      * Build db-specific report
583      * @access private
584      */
585      function _sql_report($mode, $query = '')
586      {
587          switch ($mode)
588          {
589              case 'start':
590   
591                  $html_table = false;
592   
593                  // Grab a plan table, any will do
594                  $sql = "SELECT table_name
595                      FROM USER_TABLES
596                      WHERE table_name LIKE '%PLAN_TABLE%'";
597                  $stmt = ociparse($this->db_connect_id, $sql);
598                  ociexecute($stmt);
599                  $result = array();
600   
601                  if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS))
602                  {
603                      $table = $result['TABLE_NAME'];
604   
605                      // This is the statement_id that will allow us to track the plan
606                      $statement_id = substr(md5($query), 0, 30);
607   
608                      // Remove any stale plans
609                      $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
610                      ociexecute($stmt2);
611                      ocifreestatement($stmt2);
612   
613                      // Explain the plan
614                      $sql = "EXPLAIN PLAN
615                          SET STATEMENT_ID = '$statement_id'
616                          FOR $query";
617                      $stmt2 = ociparse($this->db_connect_id, $sql);
618                      ociexecute($stmt2);
619                      ocifreestatement($stmt2);
620   
621                      // Get the data from the plan
622                      $sql = "SELECT operation, options, object_name, object_type, cardinality, cost
623                          FROM plan_table
624                          START WITH id = 0 AND statement_id = '$statement_id'
625                          CONNECT BY PRIOR id = parent_id
626                              AND statement_id = '$statement_id'";
627                      $stmt2 = ociparse($this->db_connect_id, $sql);
628                      ociexecute($stmt2);
629   
630                      $row = array();
631                      while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS))
632                      {
633                          $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
634                      }
635   
636                      ocifreestatement($stmt2);
637   
638                      // Remove the plan we just made, we delete them on request anyway
639                      $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
640                      ociexecute($stmt2);
641                      ocifreestatement($stmt2);
642                  }
643   
644                  ocifreestatement($stmt);
645   
646                  if ($html_table)
647                  {
648                      $this->html_hold .= '</table>';
649                  }
650   
651              break;
652   
653              case 'fromcache':
654                  $endtime = explode(' ', microtime());
655                  $endtime = $endtime[0] + $endtime[1];
656   
657                  $result = @ociparse($this->db_connect_id, $query);
658                  $success = @ociexecute($result, OCI_DEFAULT);
659                  $row = array();
660   
661                  while (@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS))
662                  {
663                      // Take the time spent on parsing rows into account
664                  }
665                  @ocifreestatement($result);
666   
667                  $splittime = explode(' ', microtime());
668                  $splittime = $splittime[0] + $splittime[1];
669   
670                  $this->sql_report('record_fromcache', $query, $endtime, $splittime);
671   
672              break;
673          }
674      }
675  }
676   
677  ?>