[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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('<', '>'), $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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Oct 2 15:03:47 2013 | Cross-referenced by PHPXref 0.7.1 |