[ Index ]

PHP Cross Reference of phpBB-3.2.8-deutsch

title

Body

[close]

/phpbb/db/driver/ -> driver.php (source)

   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  
  14  namespace phpbb\db\driver;
  15  
  16  /**
  17  * Database Abstraction Layer
  18  */
  19  abstract class driver implements driver_interface
  20  {
  21      var $db_connect_id;
  22      var $query_result;
  23      var $return_on_error = false;
  24      var $transaction = false;
  25      var $sql_time = 0;
  26      var $num_queries = array();
  27      var $open_queries = array();
  28  
  29      var $curtime = 0;
  30      var $query_hold = '';
  31      var $html_hold = '';
  32      var $sql_report = '';
  33  
  34      var $persistency = false;
  35      var $user = '';
  36      var $server = '';
  37      var $dbname = '';
  38  
  39      // Set to true if error triggered
  40      var $sql_error_triggered = false;
  41  
  42      // Holding the last sql query on sql error
  43      var $sql_error_sql = '';
  44      // Holding the error information - only populated if sql_error_triggered is set
  45      var $sql_error_returned = array();
  46  
  47      // Holding transaction count
  48      var $transactions = 0;
  49  
  50      // Supports multi inserts?
  51      var $multi_insert = false;
  52  
  53      /**
  54      * Current sql layer
  55      */
  56      var $sql_layer = '';
  57  
  58      /**
  59      * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions
  60      */
  61      var $any_char;
  62      var $one_char;
  63  
  64      /**
  65      * Exact version of the DBAL, directly queried
  66      */
  67      var $sql_server_version = false;
  68  
  69      const LOGICAL_OP = 0;
  70      const STATEMENTS = 1;
  71      const LEFT_STMT = 0;
  72      const COMPARE_OP = 1;
  73      const RIGHT_STMT = 2;
  74      const SUBQUERY_OP = 3;
  75      const SUBQUERY_SELECT_TYPE = 4;
  76      const SUBQUERY_BUILD = 5;
  77  
  78      /**
  79      * Constructor
  80      */
  81  	function __construct()
  82      {
  83          $this->num_queries = array(
  84              'cached'    => 0,
  85              'normal'    => 0,
  86              'total'        => 0,
  87          );
  88  
  89          // Fill default sql layer based on the class being called.
  90          // This can be changed by the specified layer itself later if needed.
  91          $this->sql_layer = substr(get_class($this), strlen('phpbb\db\driver\\'));
  92  
  93          // Do not change this please! This variable is used to easy the use of it - and is hardcoded.
  94          $this->any_char = chr(0) . '%';
  95          $this->one_char = chr(0) . '_';
  96      }
  97  
  98      /**
  99      * {@inheritdoc}
 100      */
 101  	public function get_sql_layer()
 102      {
 103          return $this->sql_layer;
 104      }
 105  
 106      /**
 107      * {@inheritdoc}
 108      */
 109  	public function get_db_name()
 110      {
 111          return $this->dbname;
 112      }
 113  
 114      /**
 115      * {@inheritdoc}
 116      */
 117  	public function get_any_char()
 118      {
 119          return $this->any_char;
 120      }
 121  
 122      /**
 123      * {@inheritdoc}
 124      */
 125  	public function get_one_char()
 126      {
 127          return $this->one_char;
 128      }
 129  
 130      /**
 131      * {@inheritdoc}
 132      */
 133  	public function get_db_connect_id()
 134      {
 135          return $this->db_connect_id;
 136      }
 137  
 138      /**
 139      * {@inheritdoc}
 140      */
 141  	public function get_sql_error_triggered()
 142      {
 143          return $this->sql_error_triggered;
 144      }
 145  
 146      /**
 147      * {@inheritdoc}
 148      */
 149  	public function get_sql_error_sql()
 150      {
 151          return $this->sql_error_sql;
 152      }
 153  
 154      /**
 155      * {@inheritdoc}
 156      */
 157  	public function get_transaction()
 158      {
 159          return $this->transaction;
 160      }
 161  
 162      /**
 163      * {@inheritdoc}
 164      */
 165  	public function get_sql_time()
 166      {
 167          return $this->sql_time;
 168      }
 169  
 170      /**
 171      * {@inheritdoc}
 172      */
 173  	public function get_sql_error_returned()
 174      {
 175          return $this->sql_error_returned;
 176      }
 177  
 178      /**
 179      * {@inheritdoc}
 180      */
 181  	public function get_multi_insert()
 182      {
 183          return $this->multi_insert;
 184      }
 185  
 186      /**
 187      * {@inheritdoc}
 188      */
 189  	public function set_multi_insert($multi_insert)
 190      {
 191          $this->multi_insert = $multi_insert;
 192      }
 193  
 194      /**
 195      * {@inheritDoc}
 196      */
 197  	function sql_return_on_error($fail = false)
 198      {
 199          $this->sql_error_triggered = false;
 200          $this->sql_error_sql = '';
 201  
 202          $this->return_on_error = $fail;
 203      }
 204  
 205      /**
 206      * {@inheritDoc}
 207      */
 208  	function sql_num_queries($cached = false)
 209      {
 210          return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal'];
 211      }
 212  
 213      /**
 214      * {@inheritDoc}
 215      */
 216  	function sql_add_num_queries($cached = false)
 217      {
 218          $this->num_queries['cached'] += ($cached !== false) ? 1 : 0;
 219          $this->num_queries['normal'] += ($cached !== false) ? 0 : 1;
 220          $this->num_queries['total'] += 1;
 221      }
 222  
 223      /**
 224      * {@inheritDoc}
 225      */
 226  	function sql_close()
 227      {
 228          if (!$this->db_connect_id)
 229          {
 230              return false;
 231          }
 232  
 233          if ($this->transaction)
 234          {
 235              do
 236              {
 237                  $this->sql_transaction('commit');
 238              }
 239              while ($this->transaction);
 240          }
 241  
 242          foreach ($this->open_queries as $query_id)
 243          {
 244              $this->sql_freeresult($query_id);
 245          }
 246  
 247          // Connection closed correctly. Set db_connect_id to false to prevent errors
 248          if ($result = $this->_sql_close())
 249          {
 250              $this->db_connect_id = false;
 251          }
 252  
 253          return $result;
 254      }
 255  
 256      /**
 257      * {@inheritDoc}
 258      */
 259  	function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
 260      {
 261          if (empty($query))
 262          {
 263              return false;
 264          }
 265  
 266          // Never use a negative total or offset
 267          $total = ($total < 0) ? 0 : $total;
 268          $offset = ($offset < 0) ? 0 : $offset;
 269  
 270          return $this->_sql_query_limit($query, $total, $offset, $cache_ttl);
 271      }
 272  
 273      /**
 274      * {@inheritDoc}
 275      */
 276  	function sql_fetchrowset($query_id = false)
 277      {
 278          if ($query_id === false)
 279          {
 280              $query_id = $this->query_result;
 281          }
 282  
 283          if ($query_id)
 284          {
 285              $result = array();
 286              while ($row = $this->sql_fetchrow($query_id))
 287              {
 288                  $result[] = $row;
 289              }
 290  
 291              return $result;
 292          }
 293  
 294          return false;
 295      }
 296  
 297      /**
 298      * {@inheritDoc}
 299      */
 300  	function sql_rowseek($rownum, &$query_id)
 301      {
 302          global $cache;
 303  
 304          if ($query_id === false)
 305          {
 306              $query_id = $this->query_result;
 307          }
 308  
 309          if ($cache && $cache->sql_exists($query_id))
 310          {
 311              return $cache->sql_rowseek($rownum, $query_id);
 312          }
 313  
 314          if (!$query_id)
 315          {
 316              return false;
 317          }
 318  
 319          $this->sql_freeresult($query_id);
 320          $query_id = $this->sql_query($this->last_query_text);
 321  
 322          if (!$query_id)
 323          {
 324              return false;
 325          }
 326  
 327          // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
 328          for ($i = 0; $i < $rownum; $i++)
 329          {
 330              if (!$this->sql_fetchrow($query_id))
 331              {
 332                  return false;
 333              }
 334          }
 335  
 336          return true;
 337      }
 338  
 339      /**
 340      * {@inheritDoc}
 341      */
 342  	function sql_fetchfield($field, $rownum = false, $query_id = false)
 343      {
 344          global $cache;
 345  
 346          if ($query_id === false)
 347          {
 348              $query_id = $this->query_result;
 349          }
 350  
 351          if ($query_id)
 352          {
 353              if ($rownum !== false)
 354              {
 355                  $this->sql_rowseek($rownum, $query_id);
 356              }
 357  
 358              if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
 359              {
 360                  return $cache->sql_fetchfield($query_id, $field);
 361              }
 362  
 363              $row = $this->sql_fetchrow($query_id);
 364              return (isset($row[$field])) ? $row[$field] : false;
 365          }
 366  
 367          return false;
 368      }
 369  
 370      /**
 371      * {@inheritDoc}
 372      */
 373  	function sql_like_expression($expression)
 374      {
 375          $expression = str_replace(array('_', '%'), array("\_", "\%"), $expression);
 376          $expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
 377  
 378          return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\'');
 379      }
 380  
 381      /**
 382      * {@inheritDoc}
 383      */
 384  	function sql_not_like_expression($expression)
 385      {
 386          $expression = str_replace(array('_', '%'), array("\_", "\%"), $expression);
 387          $expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
 388  
 389          return $this->_sql_not_like_expression('NOT LIKE \'' . $this->sql_escape($expression) . '\'');
 390      }
 391  
 392      /**
 393      * {@inheritDoc}
 394      */
 395  	public function sql_case($condition, $action_true, $action_false = false)
 396      {
 397          $sql_case = 'CASE WHEN ' . $condition;
 398          $sql_case .= ' THEN ' . $action_true;
 399          $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : '';
 400          $sql_case .= ' END';
 401          return $sql_case;
 402      }
 403  
 404      /**
 405      * {@inheritDoc}
 406      */
 407  	public function sql_concatenate($expr1, $expr2)
 408      {
 409          return $expr1 . ' || ' . $expr2;
 410      }
 411  
 412      /**
 413      * {@inheritDoc}
 414      */
 415  	function sql_buffer_nested_transactions()
 416      {
 417          return false;
 418      }
 419  
 420      /**
 421      * {@inheritDoc}
 422      */
 423  	function sql_transaction($status = 'begin')
 424      {
 425          switch ($status)
 426          {
 427              case 'begin':
 428                  // If we are within a transaction we will not open another one, but enclose the current one to not loose data (preventing auto commit)
 429                  if ($this->transaction)
 430                  {
 431                      $this->transactions++;
 432                      return true;
 433                  }
 434  
 435                  $result = $this->_sql_transaction('begin');
 436  
 437                  if (!$result)
 438                  {
 439                      $this->sql_error();
 440                  }
 441  
 442                  $this->transaction = true;
 443              break;
 444  
 445              case 'commit':
 446                  // If there was a previously opened transaction we do not commit yet...
 447                  // but count back the number of inner transactions
 448                  if ($this->transaction && $this->transactions)
 449                  {
 450                      $this->transactions--;
 451                      return true;
 452                  }
 453  
 454                  // Check if there is a transaction (no transaction can happen if
 455                  // there was an error, with a combined rollback and error returning enabled)
 456                  // This implies we have transaction always set for autocommit db's
 457                  if (!$this->transaction)
 458                  {
 459                      return false;
 460                  }
 461  
 462                  $result = $this->_sql_transaction('commit');
 463  
 464                  if (!$result)
 465                  {
 466                      $this->sql_error();
 467                  }
 468  
 469                  $this->transaction = false;
 470                  $this->transactions = 0;
 471              break;
 472  
 473              case 'rollback':
 474                  $result = $this->_sql_transaction('rollback');
 475                  $this->transaction = false;
 476                  $this->transactions = 0;
 477              break;
 478  
 479              default:
 480                  $result = $this->_sql_transaction($status);
 481              break;
 482          }
 483  
 484          return $result;
 485      }
 486  
 487      /**
 488      * {@inheritDoc}
 489      */
 490  	function sql_build_array($query, $assoc_ary = false)
 491      {
 492          if (!is_array($assoc_ary))
 493          {
 494              return false;
 495          }
 496  
 497          $fields = $values = array();
 498  
 499          if ($query == 'INSERT' || $query == 'INSERT_SELECT')
 500          {
 501              foreach ($assoc_ary as $key => $var)
 502              {
 503                  $fields[] = $key;
 504  
 505                  if (is_array($var) && is_string($var[0]))
 506                  {
 507                      // This is used for INSERT_SELECT(s)
 508                      $values[] = $var[0];
 509                  }
 510                  else
 511                  {
 512                      $values[] = $this->_sql_validate_value($var);
 513                  }
 514              }
 515  
 516              $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' ';
 517          }
 518          else if ($query == 'MULTI_INSERT')
 519          {
 520              trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR);
 521          }
 522          else if ($query == 'UPDATE' || $query == 'SELECT' || $query == 'DELETE')
 523          {
 524              $values = array();
 525              foreach ($assoc_ary as $key => $var)
 526              {
 527                  $values[] = "$key = " . $this->_sql_validate_value($var);
 528              }
 529              $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values);
 530          }
 531  
 532          return $query;
 533      }
 534  
 535      /**
 536      * {@inheritDoc}
 537      */
 538  	function sql_in_set($field, $array, $negate = false, $allow_empty_set = false)
 539      {
 540          $array = (array) $array;
 541  
 542          if (!count($array))
 543          {
 544              if (!$allow_empty_set)
 545              {
 546                  // Print the backtrace to help identifying the location of the problematic code
 547                  $this->sql_error('No values specified for SQL IN comparison');
 548              }
 549              else
 550              {
 551                  // NOT IN () actually means everything so use a tautology
 552                  if ($negate)
 553                  {
 554                      return '1=1';
 555                  }
 556                  // IN () actually means nothing so use a contradiction
 557                  else
 558                  {
 559                      return '1=0';
 560                  }
 561              }
 562          }
 563  
 564          if (count($array) == 1)
 565          {
 566              @reset($array);
 567              $var = current($array);
 568  
 569              return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var);
 570          }
 571          else
 572          {
 573              return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')';
 574          }
 575      }
 576  
 577      /**
 578      * {@inheritDoc}
 579      */
 580  	function sql_bit_and($column_name, $bit, $compare = '')
 581      {
 582          if (method_exists($this, '_sql_bit_and'))
 583          {
 584              return $this->_sql_bit_and($column_name, $bit, $compare);
 585          }
 586  
 587          return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : '');
 588      }
 589  
 590      /**
 591      * {@inheritDoc}
 592      */
 593  	function sql_bit_or($column_name, $bit, $compare = '')
 594      {
 595          if (method_exists($this, '_sql_bit_or'))
 596          {
 597              return $this->_sql_bit_or($column_name, $bit, $compare);
 598          }
 599  
 600          return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : '');
 601      }
 602  
 603      /**
 604      * {@inheritDoc}
 605      */
 606  	function cast_expr_to_bigint($expression)
 607      {
 608          return $expression;
 609      }
 610  
 611      /**
 612      * {@inheritDoc}
 613      */
 614  	function cast_expr_to_string($expression)
 615      {
 616          return $expression;
 617      }
 618  
 619      /**
 620      * {@inheritDoc}
 621      */
 622  	function sql_lower_text($column_name)
 623      {
 624          return "LOWER($column_name)";
 625      }
 626  
 627      /**
 628      * {@inheritDoc}
 629      */
 630  	function sql_multi_insert($table, $sql_ary)
 631      {
 632          if (!count($sql_ary))
 633          {
 634              return false;
 635          }
 636  
 637          if ($this->multi_insert)
 638          {
 639              $ary = array();
 640              foreach ($sql_ary as $id => $_sql_ary)
 641              {
 642                  // If by accident the sql array is only one-dimensional we build a normal insert statement
 643                  if (!is_array($_sql_ary))
 644                  {
 645                      return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary));
 646                  }
 647  
 648                  $values = array();
 649                  foreach ($_sql_ary as $key => $var)
 650                  {
 651                      $values[] = $this->_sql_validate_value($var);
 652                  }
 653                  $ary[] = '(' . implode(', ', $values) . ')';
 654              }
 655  
 656              return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary));
 657          }
 658          else
 659          {
 660              foreach ($sql_ary as $ary)
 661              {
 662                  if (!is_array($ary))
 663                  {
 664                      return false;
 665                  }
 666  
 667                  $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary));
 668  
 669                  if (!$result)
 670                  {
 671                      return false;
 672                  }
 673              }
 674          }
 675  
 676          return true;
 677      }
 678  
 679      /**
 680      * Function for validating values
 681      * @access private
 682      */
 683  	function _sql_validate_value($var)
 684      {
 685          if (is_null($var))
 686          {
 687              return 'NULL';
 688          }
 689          else if (is_string($var))
 690          {
 691              return "'" . $this->sql_escape($var) . "'";
 692          }
 693          else
 694          {
 695              return (is_bool($var)) ? intval($var) : $var;
 696          }
 697      }
 698  
 699      /**
 700      * {@inheritDoc}
 701      */
 702  	function sql_build_query($query, $array)
 703      {
 704          $sql = '';
 705          switch ($query)
 706          {
 707              case 'SELECT':
 708              case 'SELECT_DISTINCT';
 709  
 710                  $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM ';
 711  
 712                  // Build table array. We also build an alias array for later checks.
 713                  $table_array = $aliases = array();
 714                  $used_multi_alias = false;
 715  
 716                  foreach ($array['FROM'] as $table_name => $alias)
 717                  {
 718                      if (is_array($alias))
 719                      {
 720                          $used_multi_alias = true;
 721  
 722                          foreach ($alias as $multi_alias)
 723                          {
 724                              $table_array[] = $table_name . ' ' . $multi_alias;
 725                              $aliases[] = $multi_alias;
 726                          }
 727                      }
 728                      else
 729                      {
 730                          $table_array[] = $table_name . ' ' . $alias;
 731                          $aliases[] = $alias;
 732                      }
 733                  }
 734  
 735                  // We run the following code to determine if we need to re-order the table array. ;)
 736                  // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison.
 737                  // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is.
 738                  if (!empty($array['LEFT_JOIN']) && count($array['FROM']) > 1 && $used_multi_alias !== false)
 739                  {
 740                      // Take first LEFT JOIN
 741                      $join = current($array['LEFT_JOIN']);
 742  
 743                      // Determine the table used there (even if there are more than one used, we only want to have one
 744                      preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches);
 745  
 746                      // If there is a first join match, we need to make sure the table order is correct
 747                      if (!empty($matches[1]))
 748                      {
 749                          $first_join_match = trim($matches[1]);
 750                          $table_array = $last = array();
 751  
 752                          foreach ($array['FROM'] as $table_name => $alias)
 753                          {
 754                              if (is_array($alias))
 755                              {
 756                                  foreach ($alias as $multi_alias)
 757                                  {
 758                                      ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias;
 759                                  }
 760                              }
 761                              else
 762                              {
 763                                  ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias;
 764                              }
 765                          }
 766  
 767                          $table_array = array_merge($table_array, $last);
 768                      }
 769                  }
 770  
 771                  $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array));
 772  
 773                  if (!empty($array['LEFT_JOIN']))
 774                  {
 775                      foreach ($array['LEFT_JOIN'] as $join)
 776                      {
 777                          $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')';
 778                      }
 779                  }
 780  
 781                  if (!empty($array['WHERE']))
 782                  {
 783                      $sql .= ' WHERE ';
 784  
 785                      if (is_array($array['WHERE']))
 786                      {
 787                          $sql_where = $this->_process_boolean_tree_first($array['WHERE']);
 788                      }
 789                      else
 790                      {
 791                          $sql_where = $array['WHERE'];
 792                      }
 793  
 794                      $sql .= $this->_sql_custom_build('WHERE', $sql_where);
 795                  }
 796  
 797                  if (!empty($array['GROUP_BY']))
 798                  {
 799                      $sql .= ' GROUP BY ' . $array['GROUP_BY'];
 800                  }
 801  
 802                  if (!empty($array['ORDER_BY']))
 803                  {
 804                      $sql .= ' ORDER BY ' . $array['ORDER_BY'];
 805                  }
 806  
 807              break;
 808          }
 809  
 810          return $sql;
 811      }
 812  
 813  
 814  	protected function _process_boolean_tree_first($operations_ary)
 815      {
 816          // In cases where an array exists but there is no head condition,
 817          // it should be because there's only 1 WHERE clause. This seems the best way to deal with it.
 818          if ($operations_ary[self::LOGICAL_OP] !== 'AND' &&
 819              $operations_ary[self::LOGICAL_OP] !== 'OR')
 820          {
 821              $operations_ary = array('AND', array($operations_ary));
 822          }
 823          return $this->_process_boolean_tree($operations_ary) . "\n";
 824      }
 825  
 826  	protected function _process_boolean_tree($operations_ary)
 827      {
 828          $operation = $operations_ary[self::LOGICAL_OP];
 829  
 830          foreach ($operations_ary[self::STATEMENTS] as &$condition)
 831          {
 832              switch ($condition[self::LOGICAL_OP])
 833              {
 834                  case 'AND':
 835                  case 'OR':
 836  
 837                      $condition = ' ( ' . $this->_process_boolean_tree($condition) . ') ';
 838  
 839                  break;
 840                  case 'NOT':
 841  
 842                      $condition = ' NOT (' . $this->_process_boolean_tree($condition) . ') ';
 843  
 844                  break;
 845  
 846                  default:
 847  
 848                      switch (count($condition))
 849                      {
 850                          case 3:
 851  
 852                              // Typical 3 element clause with {left hand} {operator} {right hand}
 853                              switch ($condition[self::COMPARE_OP])
 854                              {
 855                                  case 'IN':
 856                                  case 'NOT_IN':
 857  
 858                                      // As this is used with an IN, assume it is a set of elements for sql_in_set()
 859                                      $condition = $this->sql_in_set($condition[self::LEFT_STMT], $condition[self::RIGHT_STMT], $condition[self::COMPARE_OP] === 'NOT_IN', true);
 860  
 861                                  break;
 862  
 863                                  case 'LIKE':
 864  
 865                                      $condition = $condition[self::LEFT_STMT] . ' ' . $this->sql_like_expression($condition[self::RIGHT_STMT]) . ' ';
 866  
 867                                  break;
 868  
 869                                  case 'NOT_LIKE':
 870  
 871                                      $condition = $condition[self::LEFT_STMT] . ' ' . $this->sql_not_like_expression($condition[self::RIGHT_STMT]) . ' ';
 872  
 873                                  break;
 874  
 875                                  case 'IS_NOT':
 876  
 877                                      $condition[self::COMPARE_OP] = 'IS NOT';
 878  
 879                                  // no break
 880                                  case 'IS':
 881  
 882                                      // If the value is NULL, the string of it is the empty string ('') which is not the intended result.
 883                                      // this should solve that
 884                                      if ($condition[self::RIGHT_STMT] === null)
 885                                      {
 886                                          $condition[self::RIGHT_STMT] = 'NULL';
 887                                      }
 888  
 889                                      $condition = implode(' ', $condition);
 890  
 891                                  break;
 892  
 893                                  default:
 894  
 895                                      $condition = implode(' ', $condition);
 896  
 897                                  break;
 898                              }
 899  
 900                          break;
 901  
 902                          case 5:
 903  
 904                              // Subquery with {left hand} {operator} {compare kind} {SELECT Kind } {Sub Query}
 905  
 906                              $result = $condition[self::LEFT_STMT] . ' ' . $condition[self::COMPARE_OP] . ' ' . $condition[self::SUBQUERY_OP] . ' ( ';
 907                              $result .= $this->sql_build_query($condition[self::SUBQUERY_SELECT_TYPE], $condition[self::SUBQUERY_BUILD]);
 908                              $result .= ' )';
 909                              $condition = $result;
 910  
 911                          break;
 912  
 913                          default:
 914                              // This is an unpredicted clause setup. Just join all elements.
 915                              $condition = implode(' ', $condition);
 916  
 917                          break;
 918                      }
 919  
 920                  break;
 921              }
 922  
 923          }
 924  
 925          if ($operation === 'NOT')
 926          {
 927              $operations_ary =  implode("", $operations_ary[self::STATEMENTS]);
 928          }
 929          else
 930          {
 931              $operations_ary = implode(" \n    $operation ", $operations_ary[self::STATEMENTS]);
 932          }
 933  
 934          return $operations_ary;
 935      }
 936  
 937  
 938      /**
 939      * {@inheritDoc}
 940      */
 941  	function sql_error($sql = '')
 942      {
 943          global $auth, $user, $config;
 944  
 945          // Set var to retrieve errored status
 946          $this->sql_error_triggered = true;
 947          $this->sql_error_sql = $sql;
 948  
 949          $this->sql_error_returned = $this->_sql_error();
 950  
 951          if (!$this->return_on_error)
 952          {
 953              $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]<br /><br />' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']';
 954  
 955              // Show complete SQL error and path to administrators only
 956              // Additionally show complete error on installation or if extended debug mode is enabled
 957              // The DEBUG constant is for development only!
 958              if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG'))
 959              {
 960                  $message .= ($sql) ? '<br /><br />SQL<br /><br />' . htmlspecialchars($sql) : '';
 961              }
 962              else
 963              {
 964                  // If error occurs in initiating the session we need to use a pre-defined language string
 965                  // This could happen if the connection could not be established for example (then we are not able to grab the default language)
 966                  if (!isset($user->lang['SQL_ERROR_OCCURRED']))
 967                  {
 968                      $message .= '<br /><br />An sql error occurred while fetching this page. Please contact an administrator if this problem persists.';
 969                  }
 970                  else
 971                  {
 972                      if (!empty($config['board_contact']))
 973                      {
 974                          $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>');
 975                      }
 976                      else
 977                      {
 978                          $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', '');
 979                      }
 980                  }
 981              }
 982  
 983              if ($this->transaction)
 984              {
 985                  $this->sql_transaction('rollback');
 986              }
 987  
 988              if (strlen($message) > 1024)
 989              {
 990                  // We need to define $msg_long_text here to circumvent text stripping.
 991                  global $msg_long_text;
 992                  $msg_long_text = $message;
 993  
 994                  trigger_error(false, E_USER_ERROR);
 995              }
 996  
 997              trigger_error($message, E_USER_ERROR);
 998          }
 999  
1000          if ($this->transaction)
1001          {
1002              $this->sql_transaction('rollback');
1003          }
1004  
1005          return $this->sql_error_returned;
1006      }
1007  
1008      /**
1009      * {@inheritDoc}
1010      */
1011  	function sql_report($mode, $query = '')
1012      {
1013          global $cache, $starttime, $phpbb_root_path, $phpbb_path_helper;
1014          global $request;
1015  
1016          if (is_object($request) && !$request->variable('explain', false))
1017          {
1018              return false;
1019          }
1020  
1021          if (!$query && $this->query_hold != '')
1022          {
1023              $query = $this->query_hold;
1024          }
1025  
1026          switch ($mode)
1027          {
1028              case 'display':
1029                  if (!empty($cache))
1030                  {
1031                      $cache->unload();
1032                  }
1033                  $this->sql_close();
1034  
1035                  $mtime = explode(' ', microtime());
1036                  $totaltime = $mtime[0] + $mtime[1] - $starttime;
1037  
1038                  echo '<!DOCTYPE html>
1039                      <html dir="ltr">
1040                      <head>
1041                          <meta charset="utf-8">
1042                          <meta http-equiv="X-UA-Compatible" content="IE=edge">
1043                          <title>SQL Report</title>
1044                          <link href="' . htmlspecialchars($phpbb_path_helper->update_web_root_path($phpbb_root_path) . $phpbb_path_helper->get_adm_relative_path()) . 'style/admin.css" rel="stylesheet" type="text/css" media="screen" />
1045                      </head>
1046                      <body id="errorpage">
1047                      <div id="wrap">
1048                          <div id="page-header">
1049                              <a href="' . build_url('explain') . '">Return to previous page</a>
1050                          </div>
1051                          <div id="page-body">
1052                              <div id="acp">
1053                              <div class="panel">
1054                                  <span class="corners-top"><span></span></span>
1055                                  <div id="content">
1056                                      <h1>SQL Report</h1>
1057                                      <br />
1058                                      <p><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></p>
1059  
1060                                      <p>Time spent on ' . $this->sql_layer . ' queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></p>
1061  
1062                                      <br /><br />
1063                                      ' . $this->sql_report . '
1064                                  </div>
1065                                  <span class="corners-bottom"><span></span></span>
1066                              </div>
1067                              </div>
1068                          </div>
1069                          <div id="page-footer">
1070                              Powered by <a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Limited
1071                          </div>
1072                      </div>
1073                      </body>
1074                      </html>';
1075  
1076                  exit_handler();
1077  
1078              break;
1079  
1080              case 'stop':
1081                  $endtime = explode(' ', microtime());
1082                  $endtime = $endtime[0] + $endtime[1];
1083  
1084                  $this->sql_report .= '
1085  
1086                      <table cellspacing="1">
1087                      <thead>
1088                      <tr>
1089                          <th>Query #' . $this->num_queries['total'] . '</th>
1090                      </tr>
1091                      </thead>
1092                      <tbody>
1093                      <tr>
1094                          <td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td>
1095                      </tr>
1096                      </tbody>
1097                      </table>
1098  
1099                      ' . $this->html_hold . '
1100  
1101                      <p style="text-align: center;">
1102                  ';
1103  
1104                  if ($this->query_result)
1105                  {
1106                      if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query))
1107                      {
1108                          $this->sql_report .= 'Affected rows: <b>' . $this->sql_affectedrows() . '</b> | ';
1109                      }
1110                      $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $this->curtime) . 's</b>';
1111                  }
1112                  else
1113                  {
1114                      $error = $this->sql_error();
1115                      $this->sql_report .= '<b style="color: red">FAILED</b> - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']);
1116                  }
1117  
1118                  $this->sql_report .= '</p><br /><br />';
1119  
1120                  $this->sql_time += $endtime - $this->curtime;
1121              break;
1122  
1123              case 'start':
1124                  $this->query_hold = $query;
1125                  $this->html_hold = '';
1126  
1127                  $this->_sql_report($mode, $query);
1128  
1129                  $this->curtime = explode(' ', microtime());
1130                  $this->curtime = $this->curtime[0] + $this->curtime[1];
1131  
1132              break;
1133  
1134              case 'add_select_row':
1135  
1136                  $html_table = func_get_arg(2);
1137                  $row = func_get_arg(3);
1138  
1139                  if (!$html_table && count($row))
1140                  {
1141                      $html_table = true;
1142                      $this->html_hold .= '<table cellspacing="1"><tr>';
1143  
1144                      foreach (array_keys($row) as $val)
1145                      {
1146                          $this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : '&nbsp;') . '</th>';
1147                      }
1148                      $this->html_hold .= '</tr>';
1149                  }
1150                  $this->html_hold .= '<tr>';
1151  
1152                  $class = 'row1';
1153                  foreach (array_values($row) as $val)
1154                  {
1155                      $class = ($class == 'row1') ? 'row2' : 'row1';
1156                      $this->html_hold .= '<td class="' . $class . '">' . (($val) ? $val : '&nbsp;') . '</td>';
1157                  }
1158                  $this->html_hold .= '</tr>';
1159  
1160                  return $html_table;
1161  
1162              break;
1163  
1164              case 'fromcache':
1165  
1166                  $this->_sql_report($mode, $query);
1167  
1168              break;
1169  
1170              case 'record_fromcache':
1171  
1172                  $endtime = func_get_arg(2);
1173                  $splittime = func_get_arg(3);
1174  
1175                  $time_cache = $endtime - $this->curtime;
1176                  $time_db = $splittime - $endtime;
1177                  $color = ($time_db > $time_cache) ? 'green' : 'red';
1178  
1179                  $this->sql_report .= '<table cellspacing="1"><thead><tr><th>Query results obtained from the cache</th></tr></thead><tbody><tr>';
1180                  $this->sql_report .= '<td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></tbody></table>';
1181                  $this->sql_report .= '<p style="text-align: center;">';
1182                  $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p><br /><br />';
1183  
1184                  // Pad the start time to not interfere with page timing
1185                  $starttime += $time_db;
1186  
1187              break;
1188  
1189              default:
1190  
1191                  $this->_sql_report($mode, $query);
1192  
1193              break;
1194          }
1195  
1196          return true;
1197      }
1198  
1199      /**
1200      * {@inheritDoc}
1201      */
1202  	function get_estimated_row_count($table_name)
1203      {
1204          return $this->get_row_count($table_name);
1205      }
1206  
1207      /**
1208      * {@inheritDoc}
1209      */
1210  	function get_row_count($table_name)
1211      {
1212          $sql = 'SELECT COUNT(*) AS rows_total
1213              FROM ' . $this->sql_escape($table_name);
1214          $result = $this->sql_query($sql);
1215          $rows_total = $this->sql_fetchfield('rows_total');
1216          $this->sql_freeresult($result);
1217  
1218          return $rows_total;
1219      }
1220  }


Generated: Sat Oct 26 11:28:42 2019 Cross-referenced by PHPXref 0.7.1