[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/includes/db/ -> mysql.php (source)

   1  <?php
   2  /**
   3  *
   4  * @package dbal
   5  * @version $Id$
   6  * @copyright (c) 2005 phpBB Group
   7  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
   8  *
   9  */
  10  
  11  /**
  12  * @ignore
  13  */
  14  if (!defined('IN_PHPBB'))
  15  {
  16      exit;
  17  }
  18  
  19  include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
  20  
  21  /**
  22  * MySQL4 Database Abstraction Layer
  23  * Compatible with:
  24  * MySQL 3.23+
  25  * MySQL 4.0+
  26  * MySQL 4.1+
  27  * MySQL 5.0+
  28  * @package dbal
  29  */
  30  class dbal_mysql extends dbal
  31  {
  32      var $multi_insert = true;
  33      var $connect_error = '';
  34  
  35      /**
  36      * Connect to server
  37      * @access public
  38      */
  39  	function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
  40      {
  41          $this->persistency = $persistency;
  42          $this->user = $sqluser;
  43          $this->server = $sqlserver . (($port) ? ':' . $port : '');
  44          $this->dbname = $database;
  45  
  46          $this->sql_layer = 'mysql4';
  47  
  48          if ($this->persistency)
  49          {
  50              if (!function_exists('mysql_pconnect'))
  51              {
  52                  $this->connect_error = 'mysql_pconnect function does not exist, is mysql extension installed?';
  53                  return $this->sql_error('');
  54              }
  55              $this->db_connect_id = @mysql_pconnect($this->server, $this->user, $sqlpassword);
  56          }
  57          else
  58          {
  59              if (!function_exists('mysql_connect'))
  60              {
  61                  $this->connect_error = 'mysql_connect function does not exist, is mysql extension installed?';
  62                  return $this->sql_error('');
  63              }
  64              $this->db_connect_id = @mysql_connect($this->server, $this->user, $sqlpassword, $new_link);
  65          }
  66  
  67          if ($this->db_connect_id && $this->dbname != '')
  68          {
  69              if (@mysql_select_db($this->dbname, $this->db_connect_id))
  70              {
  71                  // Determine what version we are using and if it natively supports UNICODE
  72                  if (version_compare($this->sql_server_info(true), '4.1.0', '>='))
  73                  {
  74                      @mysql_query("SET NAMES 'utf8'", $this->db_connect_id);
  75  
  76                      // enforce strict mode on databases that support it
  77                      if (version_compare($this->sql_server_info(true), '5.0.2', '>='))
  78                      {
  79                          $result = @mysql_query('SELECT @@session.sql_mode AS sql_mode', $this->db_connect_id);
  80                          $row = @mysql_fetch_assoc($result);
  81                          @mysql_free_result($result);
  82                          $modes = array_map('trim', explode(',', $row['sql_mode']));
  83  
  84                          // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES
  85                          if (!in_array('TRADITIONAL', $modes))
  86                          {
  87                              if (!in_array('STRICT_ALL_TABLES', $modes))
  88                              {
  89                                  $modes[] = 'STRICT_ALL_TABLES';
  90                              }
  91  
  92                              if (!in_array('STRICT_TRANS_TABLES', $modes))
  93                              {
  94                                  $modes[] = 'STRICT_TRANS_TABLES';
  95                              }
  96                          }
  97  
  98                          $mode = implode(',', $modes);
  99                          @mysql_query("SET SESSION sql_mode='{$mode}'", $this->db_connect_id);
 100                      }
 101                  }
 102                  else if (version_compare($this->sql_server_info(true), '4.0.0', '<'))
 103                  {
 104                      $this->sql_layer = 'mysql';
 105                  }
 106  
 107                  return $this->db_connect_id;
 108              }
 109          }
 110  
 111          return $this->sql_error('');
 112      }
 113  
 114      /**
 115      * Version information about used database
 116      * @param bool $raw if true, only return the fetched sql_server_version
 117      * @param bool $use_cache If true, it is safe to retrieve the value from the cache
 118      * @return string sql server version
 119      */
 120  	function sql_server_info($raw = false, $use_cache = true)
 121      {
 122          global $cache;
 123  
 124          if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysql_version')) === false)
 125          {
 126              $result = @mysql_query('SELECT VERSION() AS version', $this->db_connect_id);
 127              $row = @mysql_fetch_assoc($result);
 128              @mysql_free_result($result);
 129  
 130              $this->sql_server_version = $row['version'];
 131  
 132              if (!empty($cache) && $use_cache)
 133              {
 134                  $cache->put('mysql_version', $this->sql_server_version);
 135              }
 136          }
 137  
 138          return ($raw) ? $this->sql_server_version : 'MySQL ' . $this->sql_server_version;
 139      }
 140  
 141      /**
 142      * SQL Transaction
 143      * @access private
 144      */
 145  	function _sql_transaction($status = 'begin')
 146      {
 147          switch ($status)
 148          {
 149              case 'begin':
 150                  return @mysql_query('BEGIN', $this->db_connect_id);
 151              break;
 152  
 153              case 'commit':
 154                  return @mysql_query('COMMIT', $this->db_connect_id);
 155              break;
 156  
 157              case 'rollback':
 158                  return @mysql_query('ROLLBACK', $this->db_connect_id);
 159              break;
 160          }
 161  
 162          return true;
 163      }
 164  
 165      /**
 166      * Base query method
 167      *
 168      * @param    string    $query        Contains the SQL query which shall be executed
 169      * @param    int        $cache_ttl    Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
 170      * @return    mixed                When casted to bool the returned value returns true on success and false on failure
 171      *
 172      * @access    public
 173      */
 174  	function sql_query($query = '', $cache_ttl = 0)
 175      {
 176          if ($query != '')
 177          {
 178              global $cache;
 179  
 180              // EXPLAIN only in extra debug mode
 181              if (defined('DEBUG_EXTRA'))
 182              {
 183                  $this->sql_report('start', $query);
 184              }
 185  
 186              $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false;
 187              $this->sql_add_num_queries($this->query_result);
 188  
 189              if ($this->query_result === false)
 190              {
 191                  if (($this->query_result = @mysql_query($query, $this->db_connect_id)) === false)
 192                  {
 193                      $this->sql_error($query);
 194                  }
 195  
 196                  if (defined('DEBUG_EXTRA'))
 197                  {
 198                      $this->sql_report('stop', $query);
 199                  }
 200  
 201                  if ($cache_ttl && method_exists($cache, 'sql_save'))
 202                  {
 203                      $this->open_queries[(int) $this->query_result] = $this->query_result;
 204                      $cache->sql_save($query, $this->query_result, $cache_ttl);
 205                  }
 206                  else if (strpos($query, 'SELECT') === 0 && $this->query_result)
 207                  {
 208                      $this->open_queries[(int) $this->query_result] = $this->query_result;
 209                  }
 210              }
 211              else if (defined('DEBUG_EXTRA'))
 212              {
 213                  $this->sql_report('fromcache', $query);
 214              }
 215          }
 216          else
 217          {
 218              return false;
 219          }
 220  
 221          return $this->query_result;
 222      }
 223  
 224      /**
 225      * Build LIMIT query
 226      */
 227  	function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
 228      {
 229          $this->query_result = false;
 230  
 231          // if $total is set to 0 we do not want to limit the number of rows
 232          if ($total == 0)
 233          {
 234              // Having a value of -1 was always a bug
 235              $total = '18446744073709551615';
 236          }
 237  
 238          $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
 239  
 240          return $this->sql_query($query, $cache_ttl);
 241      }
 242  
 243      /**
 244      * Return number of affected rows
 245      */
 246  	function sql_affectedrows()
 247      {
 248          return ($this->db_connect_id) ? @mysql_affected_rows($this->db_connect_id) : false;
 249      }
 250  
 251      /**
 252      * Fetch current row
 253      */
 254  	function sql_fetchrow($query_id = false)
 255      {
 256          global $cache;
 257  
 258          if ($query_id === false)
 259          {
 260              $query_id = $this->query_result;
 261          }
 262  
 263          if (isset($cache->sql_rowset[$query_id]))
 264          {
 265              return $cache->sql_fetchrow($query_id);
 266          }
 267  
 268          return ($query_id !== false) ? @mysql_fetch_assoc($query_id) : false;
 269      }
 270  
 271      /**
 272      * Seek to given row number
 273      * rownum is zero-based
 274      */
 275  	function sql_rowseek($rownum, &$query_id)
 276      {
 277          global $cache;
 278  
 279          if ($query_id === false)
 280          {
 281              $query_id = $this->query_result;
 282          }
 283  
 284          if (isset($cache->sql_rowset[$query_id]))
 285          {
 286              return $cache->sql_rowseek($rownum, $query_id);
 287          }
 288  
 289          return ($query_id !== false) ? @mysql_data_seek($query_id, $rownum) : false;
 290      }
 291  
 292      /**
 293      * Get last inserted id after insert statement
 294      */
 295  	function sql_nextid()
 296      {
 297          return ($this->db_connect_id) ? @mysql_insert_id($this->db_connect_id) : false;
 298      }
 299  
 300      /**
 301      * Free sql result
 302      */
 303  	function sql_freeresult($query_id = false)
 304      {
 305          global $cache;
 306  
 307          if ($query_id === false)
 308          {
 309              $query_id = $this->query_result;
 310          }
 311  
 312          if (isset($cache->sql_rowset[$query_id]))
 313          {
 314              return $cache->sql_freeresult($query_id);
 315          }
 316  
 317          if (isset($this->open_queries[(int) $query_id]))
 318          {
 319              unset($this->open_queries[(int) $query_id]);
 320              return @mysql_free_result($query_id);
 321          }
 322  
 323          return false;
 324      }
 325  
 326      /**
 327      * Escape string used in sql query
 328      */
 329  	function sql_escape($msg)
 330      {
 331          if (!$this->db_connect_id)
 332          {
 333              return @mysql_real_escape_string($msg);
 334          }
 335  
 336          return @mysql_real_escape_string($msg, $this->db_connect_id);
 337      }
 338  
 339      /**
 340      * Gets the estimated number of rows in a specified table.
 341      *
 342      * @param string $table_name        Table name
 343      *
 344      * @return string                Number of rows in $table_name.
 345      *                                Prefixed with ~ if estimated (otherwise exact).
 346      *
 347      * @access public
 348      */
 349  	function get_estimated_row_count($table_name)
 350      {
 351          $table_status = $this->get_table_status($table_name);
 352  
 353          if (isset($table_status['Engine']))
 354          {
 355              if ($table_status['Engine'] === 'MyISAM')
 356              {
 357                  return $table_status['Rows'];
 358              }
 359              else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000)
 360              {
 361                  return '~' . $table_status['Rows'];
 362              }
 363          }
 364  
 365          return parent::get_row_count($table_name);
 366      }
 367  
 368      /**
 369      * Gets the exact number of rows in a specified table.
 370      *
 371      * @param string $table_name        Table name
 372      *
 373      * @return string                Exact number of rows in $table_name.
 374      *
 375      * @access public
 376      */
 377  	function get_row_count($table_name)
 378      {
 379          $table_status = $this->get_table_status($table_name);
 380  
 381          if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM')
 382          {
 383              return $table_status['Rows'];
 384          }
 385  
 386          return parent::get_row_count($table_name);
 387      }
 388  
 389      /**
 390      * Gets some information about the specified table.
 391      *
 392      * @param string $table_name        Table name
 393      *
 394      * @return array
 395      *
 396      * @access protected
 397      */
 398  	function get_table_status($table_name)
 399      {
 400          $sql = "SHOW TABLE STATUS
 401              LIKE '" . $this->sql_escape($table_name) . "'";
 402          $result = $this->sql_query($sql);
 403          $table_status = $this->sql_fetchrow($result);
 404          $this->sql_freeresult($result);
 405  
 406          return $table_status;
 407      }
 408  
 409      /**
 410      * Build LIKE expression
 411      * @access private
 412      */
 413  	function _sql_like_expression($expression)
 414      {
 415          return $expression;
 416      }
 417  
 418      /**
 419      * Build db-specific query data
 420      * @access private
 421      */
 422  	function _sql_custom_build($stage, $data)
 423      {
 424          switch ($stage)
 425          {
 426              case 'FROM':
 427                  $data = '(' . $data . ')';
 428              break;
 429          }
 430  
 431          return $data;
 432      }
 433  
 434      /**
 435      * return sql error array
 436      * @access private
 437      */
 438  	function _sql_error()
 439      {
 440          if ($this->db_connect_id)
 441          {
 442              $error = array(
 443                  'message'    => @mysql_error($this->db_connect_id),
 444                  'code'        => @mysql_errno($this->db_connect_id),
 445              );
 446          }
 447          else if (function_exists('mysql_error'))
 448          {
 449              $error = array(
 450                  'message'    => @mysql_error(),
 451                  'code'        => @mysql_errno(),
 452              );
 453          }
 454          else
 455          {
 456              $error = array(
 457                  'message'    => $this->connect_error,
 458                  'code'        => '',
 459              );
 460          }
 461  
 462          return $error;
 463      }
 464  
 465      /**
 466      * Close sql connection
 467      * @access private
 468      */
 469  	function _sql_close()
 470      {
 471          return @mysql_close($this->db_connect_id);
 472      }
 473  
 474      /**
 475      * Build db-specific report
 476      * @access private
 477      */
 478  	function _sql_report($mode, $query = '')
 479      {
 480          static $test_prof;
 481  
 482          // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING
 483          if ($test_prof === null)
 484          {
 485              $test_prof = false;
 486              if (version_compare($this->sql_server_info(true), '5.0.37', '>=') && version_compare($this->sql_server_info(true), '5.1', '<'))
 487              {
 488                  $test_prof = true;
 489              }
 490          }
 491  
 492          switch ($mode)
 493          {
 494              case 'start':
 495  
 496                  $explain_query = $query;
 497                  if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
 498                  {
 499                      $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
 500                  }
 501                  else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
 502                  {
 503                      $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
 504                  }
 505  
 506                  if (preg_match('/^SELECT/', $explain_query))
 507                  {
 508                      $html_table = false;
 509  
 510                      // begin profiling
 511                      if ($test_prof)
 512                      {
 513                          @mysql_query('SET profiling = 1;', $this->db_connect_id);
 514                      }
 515  
 516                      if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id))
 517                      {
 518                          while ($row = @mysql_fetch_assoc($result))
 519                          {
 520                              $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
 521                          }
 522                      }
 523                      @mysql_free_result($result);
 524  
 525                      if ($html_table)
 526                      {
 527                          $this->html_hold .= '</table>';
 528                      }
 529  
 530                      if ($test_prof)
 531                      {
 532                          $html_table = false;
 533  
 534                          // get the last profile
 535                          if ($result = @mysql_query('SHOW PROFILE ALL;', $this->db_connect_id))
 536                          {
 537                              $this->html_hold .= '<br />';
 538                              while ($row = @mysql_fetch_assoc($result))
 539                              {
 540                                  // make <unknown> HTML safe
 541                                  if (!empty($row['Source_function']))
 542                                  {
 543                                      $row['Source_function'] = str_replace(array('<', '>'), array('&lt;', '&gt;'), $row['Source_function']);
 544                                  }
 545  
 546                                  // remove unsupported features
 547                                  foreach ($row as $key => $val)
 548                                  {
 549                                      if ($val === null)
 550                                      {
 551                                          unset($row[$key]);
 552                                      }
 553                                  }
 554                                  $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
 555                              }
 556                          }
 557                          @mysql_free_result($result);
 558  
 559                          if ($html_table)
 560                          {
 561                              $this->html_hold .= '</table>';
 562                          }
 563  
 564                          @mysql_query('SET profiling = 0;', $this->db_connect_id);
 565                      }
 566                  }
 567  
 568              break;
 569  
 570              case 'fromcache':
 571                  $endtime = explode(' ', microtime());
 572                  $endtime = $endtime[0] + $endtime[1];
 573  
 574                  $result = @mysql_query($query, $this->db_connect_id);
 575                  while ($void = @mysql_fetch_assoc($result))
 576                  {
 577                      // Take the time spent on parsing rows into account
 578                  }
 579                  @mysql_free_result($result);
 580  
 581                  $splittime = explode(' ', microtime());
 582                  $splittime = $splittime[0] + $splittime[1];
 583  
 584                  $this->sql_report('record_fromcache', $query, $endtime, $splittime);
 585  
 586              break;
 587          }
 588      }
 589  }
 590  
 591  ?>


Generated: Wed Oct 2 15:03:47 2013 Cross-referenced by PHPXref 0.7.1