[ 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 /** 20 * Database Abstraction Layer 21 * @package dbal 22 */ 23 class dbal 24 { 25 var $db_connect_id; 26 var $query_result; 27 var $return_on_error = false; 28 var $transaction = false; 29 var $sql_time = 0; 30 var $num_queries = array(); 31 var $open_queries = array(); 32 33 var $curtime = 0; 34 var $query_hold = ''; 35 var $html_hold = ''; 36 var $sql_report = ''; 37 38 var $persistency = false; 39 var $user = ''; 40 var $server = ''; 41 var $dbname = ''; 42 43 // Set to true if error triggered 44 var $sql_error_triggered = false; 45 46 // Holding the last sql query on sql error 47 var $sql_error_sql = ''; 48 // Holding the error information - only populated if sql_error_triggered is set 49 var $sql_error_returned = array(); 50 51 // Holding transaction count 52 var $transactions = 0; 53 54 // Supports multi inserts? 55 var $multi_insert = false; 56 57 /** 58 * Current sql layer 59 */ 60 var $sql_layer = ''; 61 62 /** 63 * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions 64 */ 65 var $any_char; 66 var $one_char; 67 68 /** 69 * Exact version of the DBAL, directly queried 70 */ 71 var $sql_server_version = false; 72 73 /** 74 * Constructor 75 */ 76 function dbal() 77 { 78 $this->num_queries = array( 79 'cached' => 0, 80 'normal' => 0, 81 'total' => 0, 82 ); 83 84 // Fill default sql layer based on the class being called. 85 // This can be changed by the specified layer itself later if needed. 86 $this->sql_layer = substr(get_class($this), 5); 87 88 // Do not change this please! This variable is used to easy the use of it - and is hardcoded. 89 $this->any_char = chr(0) . '%'; 90 $this->one_char = chr(0) . '_'; 91 } 92 93 /** 94 * return on error or display error message 95 */ 96 function sql_return_on_error($fail = false) 97 { 98 $this->sql_error_triggered = false; 99 $this->sql_error_sql = ''; 100 101 $this->return_on_error = $fail; 102 } 103 104 /** 105 * Return number of sql queries and cached sql queries used 106 */ 107 function sql_num_queries($cached = false) 108 { 109 return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; 110 } 111 112 /** 113 * Add to query count 114 */ 115 function sql_add_num_queries($cached = false) 116 { 117 $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; 118 $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; 119 $this->num_queries['total'] += 1; 120 } 121 122 /** 123 * DBAL garbage collection, close sql connection 124 */ 125 function sql_close() 126 { 127 if (!$this->db_connect_id) 128 { 129 return false; 130 } 131 132 if ($this->transaction) 133 { 134 do 135 { 136 $this->sql_transaction('commit'); 137 } 138 while ($this->transaction); 139 } 140 141 foreach ($this->open_queries as $query_id) 142 { 143 $this->sql_freeresult($query_id); 144 } 145 146 // Connection closed correctly. Set db_connect_id to false to prevent errors 147 if ($result = $this->_sql_close()) 148 { 149 $this->db_connect_id = false; 150 } 151 152 return $result; 153 } 154 155 /** 156 * Build LIMIT query 157 * Doing some validation here. 158 */ 159 function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) 160 { 161 if (empty($query)) 162 { 163 return false; 164 } 165 166 // Never use a negative total or offset 167 $total = ($total < 0) ? 0 : $total; 168 $offset = ($offset < 0) ? 0 : $offset; 169 170 return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); 171 } 172 173 /** 174 * Fetch all rows 175 */ 176 function sql_fetchrowset($query_id = false) 177 { 178 if ($query_id === false) 179 { 180 $query_id = $this->query_result; 181 } 182 183 if ($query_id !== false) 184 { 185 $result = array(); 186 while ($row = $this->sql_fetchrow($query_id)) 187 { 188 $result[] = $row; 189 } 190 191 return $result; 192 } 193 194 return false; 195 } 196 197 /** 198 * Seek to given row number 199 * rownum is zero-based 200 */ 201 function sql_rowseek($rownum, &$query_id) 202 { 203 global $cache; 204 205 if ($query_id === false) 206 { 207 $query_id = $this->query_result; 208 } 209 210 if (isset($cache->sql_rowset[$query_id])) 211 { 212 return $cache->sql_rowseek($rownum, $query_id); 213 } 214 215 if ($query_id === false) 216 { 217 return false; 218 } 219 220 $this->sql_freeresult($query_id); 221 $query_id = $this->sql_query($this->last_query_text); 222 223 if ($query_id === false) 224 { 225 return false; 226 } 227 228 // We do not fetch the row for rownum == 0 because then the next resultset would be the second row 229 for ($i = 0; $i < $rownum; $i++) 230 { 231 if (!$this->sql_fetchrow($query_id)) 232 { 233 return false; 234 } 235 } 236 237 return true; 238 } 239 240 /** 241 * Fetch field 242 * if rownum is false, the current row is used, else it is pointing to the row (zero-based) 243 */ 244 function sql_fetchfield($field, $rownum = false, $query_id = false) 245 { 246 global $cache; 247 248 if ($query_id === false) 249 { 250 $query_id = $this->query_result; 251 } 252 253 if ($query_id !== false) 254 { 255 if ($rownum !== false) 256 { 257 $this->sql_rowseek($rownum, $query_id); 258 } 259 260 if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) 261 { 262 return $cache->sql_fetchfield($query_id, $field); 263 } 264 265 $row = $this->sql_fetchrow($query_id); 266 return (isset($row[$field])) ? $row[$field] : false; 267 } 268 269 return false; 270 } 271 272 /** 273 * Correctly adjust LIKE expression for special characters 274 * Some DBMS are handling them in a different way 275 * 276 * @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char 277 * @return string LIKE expression including the keyword! 278 */ 279 function sql_like_expression($expression) 280 { 281 $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); 282 $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); 283 284 return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); 285 } 286 287 /** 288 * Returns whether results of a query need to be buffered to run a transaction while iterating over them. 289 * 290 * @return bool Whether buffering is required. 291 */ 292 function sql_buffer_nested_transactions() 293 { 294 return false; 295 } 296 297 /** 298 * SQL Transaction 299 * @access private 300 */ 301 function sql_transaction($status = 'begin') 302 { 303 switch ($status) 304 { 305 case 'begin': 306 // If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit) 307 if ($this->transaction) 308 { 309 $this->transactions++; 310 return true; 311 } 312 313 $result = $this->_sql_transaction('begin'); 314 315 if (!$result) 316 { 317 $this->sql_error(); 318 } 319 320 $this->transaction = true; 321 break; 322 323 case 'commit': 324 // If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions 325 if ($this->transaction && $this->transactions) 326 { 327 $this->transactions--; 328 return true; 329 } 330 331 // Check if there is a transaction (no transaction can happen if there was an error, with a combined rollback and error returning enabled) 332 // This implies we have transaction always set for autocommit db's 333 if (!$this->transaction) 334 { 335 return false; 336 } 337 338 $result = $this->_sql_transaction('commit'); 339 340 if (!$result) 341 { 342 $this->sql_error(); 343 } 344 345 $this->transaction = false; 346 $this->transactions = 0; 347 break; 348 349 case 'rollback': 350 $result = $this->_sql_transaction('rollback'); 351 $this->transaction = false; 352 $this->transactions = 0; 353 break; 354 355 default: 356 $result = $this->_sql_transaction($status); 357 break; 358 } 359 360 return $result; 361 } 362 363 /** 364 * Build sql statement from array for insert/update/select statements 365 * 366 * Idea for this from Ikonboard 367 * Possible query values: INSERT, INSERT_SELECT, UPDATE, SELECT 368 * 369 */ 370 function sql_build_array($query, $assoc_ary = false) 371 { 372 if (!is_array($assoc_ary)) 373 { 374 return false; 375 } 376 377 $fields = $values = array(); 378 379 if ($query == 'INSERT' || $query == 'INSERT_SELECT') 380 { 381 foreach ($assoc_ary as $key => $var) 382 { 383 $fields[] = $key; 384 385 if (is_array($var) && is_string($var[0])) 386 { 387 // This is used for INSERT_SELECT(s) 388 $values[] = $var[0]; 389 } 390 else 391 { 392 $values[] = $this->_sql_validate_value($var); 393 } 394 } 395 396 $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; 397 } 398 else if ($query == 'MULTI_INSERT') 399 { 400 trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); 401 } 402 else if ($query == 'UPDATE' || $query == 'SELECT') 403 { 404 $values = array(); 405 foreach ($assoc_ary as $key => $var) 406 { 407 $values[] = "$key = " . $this->_sql_validate_value($var); 408 } 409 $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); 410 } 411 412 return $query; 413 } 414 415 /** 416 * Build IN or NOT IN sql comparison string, uses <> or = on single element 417 * arrays to improve comparison speed 418 * 419 * @access public 420 * @param string $field name of the sql column that shall be compared 421 * @param array $array array of values that are allowed (IN) or not allowed (NOT IN) 422 * @param bool $negate true for NOT IN (), false for IN () (default) 423 * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false. 424 */ 425 function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) 426 { 427 if (!sizeof($array)) 428 { 429 if (!$allow_empty_set) 430 { 431 // Print the backtrace to help identifying the location of the problematic code 432 $this->sql_error('No values specified for SQL IN comparison'); 433 } 434 else 435 { 436 // NOT IN () actually means everything so use a tautology 437 if ($negate) 438 { 439 return '1=1'; 440 } 441 // IN () actually means nothing so use a contradiction 442 else 443 { 444 return '1=0'; 445 } 446 } 447 } 448 449 if (!is_array($array)) 450 { 451 $array = array($array); 452 } 453 454 if (sizeof($array) == 1) 455 { 456 @reset($array); 457 $var = current($array); 458 459 return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); 460 } 461 else 462 { 463 return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; 464 } 465 } 466 467 /** 468 * Run binary AND operator on DB column. 469 * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" 470 * 471 * @param string $column_name The column name to use 472 * @param int $bit The value to use for the AND operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 473 * @param string $compare Any custom SQL code after the check (for example "= 0") 474 */ 475 function sql_bit_and($column_name, $bit, $compare = '') 476 { 477 if (method_exists($this, '_sql_bit_and')) 478 { 479 return $this->_sql_bit_and($column_name, $bit, $compare); 480 } 481 482 return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); 483 } 484 485 /** 486 * Run binary OR operator on DB column. 487 * Results in sql statement: "{$column_name} | (1 << {$bit}) {$compare}" 488 * 489 * @param string $column_name The column name to use 490 * @param int $bit The value to use for the OR operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 491 * @param string $compare Any custom SQL code after the check (for example "= 0") 492 */ 493 function sql_bit_or($column_name, $bit, $compare = '') 494 { 495 if (method_exists($this, '_sql_bit_or')) 496 { 497 return $this->_sql_bit_or($column_name, $bit, $compare); 498 } 499 500 return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); 501 } 502 503 /** 504 * Run LOWER() on DB column of type text (i.e. neither varchar nor char). 505 * 506 * @param string $column_name The column name to use 507 * 508 * @return string A SQL statement like "LOWER($column_name)" 509 */ 510 function sql_lower_text($column_name) 511 { 512 return "LOWER($column_name)"; 513 } 514 515 /** 516 * Run more than one insert statement. 517 * 518 * @param string $table table name to run the statements on 519 * @param array &$sql_ary multi-dimensional array holding the statement data. 520 * 521 * @return bool false if no statements were executed. 522 * @access public 523 */ 524 function sql_multi_insert($table, &$sql_ary) 525 { 526 if (!sizeof($sql_ary)) 527 { 528 return false; 529 } 530 531 if ($this->multi_insert) 532 { 533 $ary = array(); 534 foreach ($sql_ary as $id => $_sql_ary) 535 { 536 // If by accident the sql array is only one-dimensional we build a normal insert statement 537 if (!is_array($_sql_ary)) 538 { 539 return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); 540 } 541 542 $values = array(); 543 foreach ($_sql_ary as $key => $var) 544 { 545 $values[] = $this->_sql_validate_value($var); 546 } 547 $ary[] = '(' . implode(', ', $values) . ')'; 548 } 549 550 return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); 551 } 552 else 553 { 554 foreach ($sql_ary as $ary) 555 { 556 if (!is_array($ary)) 557 { 558 return false; 559 } 560 561 $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); 562 563 if (!$result) 564 { 565 return false; 566 } 567 } 568 } 569 570 return true; 571 } 572 573 /** 574 * Function for validating values 575 * @access private 576 */ 577 function _sql_validate_value($var) 578 { 579 if (is_null($var)) 580 { 581 return 'NULL'; 582 } 583 else if (is_string($var)) 584 { 585 return "'" . $this->sql_escape($var) . "'"; 586 } 587 else 588 { 589 return (is_bool($var)) ? intval($var) : $var; 590 } 591 } 592 593 /** 594 * Build sql statement from array for select and select distinct statements 595 * 596 * Possible query values: SELECT, SELECT_DISTINCT 597 */ 598 function sql_build_query($query, $array) 599 { 600 $sql = ''; 601 switch ($query) 602 { 603 case 'SELECT': 604 case 'SELECT_DISTINCT'; 605 606 $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; 607 608 // Build table array. We also build an alias array for later checks. 609 $table_array = $aliases = array(); 610 $used_multi_alias = false; 611 612 foreach ($array['FROM'] as $table_name => $alias) 613 { 614 if (is_array($alias)) 615 { 616 $used_multi_alias = true; 617 618 foreach ($alias as $multi_alias) 619 { 620 $table_array[] = $table_name . ' ' . $multi_alias; 621 $aliases[] = $multi_alias; 622 } 623 } 624 else 625 { 626 $table_array[] = $table_name . ' ' . $alias; 627 $aliases[] = $alias; 628 } 629 } 630 631 // We run the following code to determine if we need to re-order the table array. ;) 632 // 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. 633 // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. 634 if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false) 635 { 636 // Take first LEFT JOIN 637 $join = current($array['LEFT_JOIN']); 638 639 // Determine the table used there (even if there are more than one used, we only want to have one 640 preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); 641 642 // If there is a first join match, we need to make sure the table order is correct 643 if (!empty($matches[1])) 644 { 645 $first_join_match = trim($matches[1]); 646 $table_array = $last = array(); 647 648 foreach ($array['FROM'] as $table_name => $alias) 649 { 650 if (is_array($alias)) 651 { 652 foreach ($alias as $multi_alias) 653 { 654 ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; 655 } 656 } 657 else 658 { 659 ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; 660 } 661 } 662 663 $table_array = array_merge($table_array, $last); 664 } 665 } 666 667 $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); 668 669 if (!empty($array['LEFT_JOIN'])) 670 { 671 foreach ($array['LEFT_JOIN'] as $join) 672 { 673 $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; 674 } 675 } 676 677 if (!empty($array['WHERE'])) 678 { 679 $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']); 680 } 681 682 if (!empty($array['GROUP_BY'])) 683 { 684 $sql .= ' GROUP BY ' . $array['GROUP_BY']; 685 } 686 687 if (!empty($array['ORDER_BY'])) 688 { 689 $sql .= ' ORDER BY ' . $array['ORDER_BY']; 690 } 691 692 break; 693 } 694 695 return $sql; 696 } 697 698 /** 699 * display sql error page 700 */ 701 function sql_error($sql = '') 702 { 703 global $auth, $user, $config; 704 705 // Set var to retrieve errored status 706 $this->sql_error_triggered = true; 707 $this->sql_error_sql = $sql; 708 709 $this->sql_error_returned = $this->_sql_error(); 710 711 if (!$this->return_on_error) 712 { 713 $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]<br /><br />' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; 714 715 // Show complete SQL error and path to administrators only 716 // Additionally show complete error on installation or if extended debug mode is enabled 717 // The DEBUG_EXTRA constant is for development only! 718 if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG_EXTRA')) 719 { 720 $message .= ($sql) ? '<br /><br />SQL<br /><br />' . htmlspecialchars($sql) : ''; 721 } 722 else 723 { 724 // If error occurs in initiating the session we need to use a pre-defined language string 725 // This could happen if the connection could not be established for example (then we are not able to grab the default language) 726 if (!isset($user->lang['SQL_ERROR_OCCURRED'])) 727 { 728 $message .= '<br /><br />An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; 729 } 730 else 731 { 732 if (!empty($config['board_contact'])) 733 { 734 $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'); 735 } 736 else 737 { 738 $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); 739 } 740 } 741 } 742 743 if ($this->transaction) 744 { 745 $this->sql_transaction('rollback'); 746 } 747 748 if (strlen($message) > 1024) 749 { 750 // We need to define $msg_long_text here to circumvent text stripping. 751 global $msg_long_text; 752 $msg_long_text = $message; 753 754 trigger_error(false, E_USER_ERROR); 755 } 756 757 trigger_error($message, E_USER_ERROR); 758 } 759 760 if ($this->transaction) 761 { 762 $this->sql_transaction('rollback'); 763 } 764 765 return $this->sql_error_returned; 766 } 767 768 /** 769 * Explain queries 770 */ 771 function sql_report($mode, $query = '') 772 { 773 global $cache, $starttime, $phpbb_root_path, $user; 774 775 if (empty($_REQUEST['explain'])) 776 { 777 return false; 778 } 779 780 if (!$query && $this->query_hold != '') 781 { 782 $query = $this->query_hold; 783 } 784 785 switch ($mode) 786 { 787 case 'display': 788 if (!empty($cache)) 789 { 790 $cache->unload(); 791 } 792 $this->sql_close(); 793 794 $mtime = explode(' ', microtime()); 795 $totaltime = $mtime[0] + $mtime[1] - $starttime; 796 797 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 798 <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr"> 799 <head> 800 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> 801 <meta http-equiv="Content-Style-Type" content="text/css" /> 802 <meta http-equiv="imagetoolbar" content="no" /> 803 <title>SQL Report</title> 804 <link href="' . $phpbb_root_path . 'adm/style/admin.css" rel="stylesheet" type="text/css" media="screen" /> 805 </head> 806 <body id="errorpage"> 807 <div id="wrap"> 808 <div id="page-header"> 809 <a href="' . build_url('explain') . '">Return to previous page</a> 810 </div> 811 <div id="page-body"> 812 <div id="acp"> 813 <div class="panel"> 814 <span class="corners-top"><span></span></span> 815 <div id="content"> 816 <h1>SQL Report</h1> 817 <br /> 818 <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> 819 820 <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> 821 822 <br /><br /> 823 ' . $this->sql_report . ' 824 </div> 825 <span class="corners-bottom"><span></span></span> 826 </div> 827 </div> 828 </div> 829 <div id="page-footer"> 830 Powered by <a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Group 831 </div> 832 </div> 833 </body> 834 </html>'; 835 836 exit_handler(); 837 838 break; 839 840 case 'stop': 841 $endtime = explode(' ', microtime()); 842 $endtime = $endtime[0] + $endtime[1]; 843 844 $this->sql_report .= ' 845 846 <table cellspacing="1"> 847 <thead> 848 <tr> 849 <th>Query #' . $this->num_queries['total'] . '</th> 850 </tr> 851 </thead> 852 <tbody> 853 <tr> 854 <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> 855 </tr> 856 </tbody> 857 </table> 858 859 ' . $this->html_hold . ' 860 861 <p style="text-align: center;"> 862 '; 863 864 if ($this->query_result) 865 { 866 if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) 867 { 868 $this->sql_report .= 'Affected rows: <b>' . $this->sql_affectedrows($this->query_result) . '</b> | '; 869 } 870 $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>'; 871 } 872 else 873 { 874 $error = $this->sql_error(); 875 $this->sql_report .= '<b style="color: red">FAILED</b> - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); 876 } 877 878 $this->sql_report .= '</p><br /><br />'; 879 880 $this->sql_time += $endtime - $this->curtime; 881 break; 882 883 case 'start': 884 $this->query_hold = $query; 885 $this->html_hold = ''; 886 887 $this->_sql_report($mode, $query); 888 889 $this->curtime = explode(' ', microtime()); 890 $this->curtime = $this->curtime[0] + $this->curtime[1]; 891 892 break; 893 894 case 'add_select_row': 895 896 $html_table = func_get_arg(2); 897 $row = func_get_arg(3); 898 899 if (!$html_table && sizeof($row)) 900 { 901 $html_table = true; 902 $this->html_hold .= '<table cellspacing="1"><tr>'; 903 904 foreach (array_keys($row) as $val) 905 { 906 $this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '</th>'; 907 } 908 $this->html_hold .= '</tr>'; 909 } 910 $this->html_hold .= '<tr>'; 911 912 $class = 'row1'; 913 foreach (array_values($row) as $val) 914 { 915 $class = ($class == 'row1') ? 'row2' : 'row1'; 916 $this->html_hold .= '<td class="' . $class . '">' . (($val) ? $val : ' ') . '</td>'; 917 } 918 $this->html_hold .= '</tr>'; 919 920 return $html_table; 921 922 break; 923 924 case 'fromcache': 925 926 $this->_sql_report($mode, $query); 927 928 break; 929 930 case 'record_fromcache': 931 932 $endtime = func_get_arg(2); 933 $splittime = func_get_arg(3); 934 935 $time_cache = $endtime - $this->curtime; 936 $time_db = $splittime - $endtime; 937 $color = ($time_db > $time_cache) ? 'green' : 'red'; 938 939 $this->sql_report .= '<table cellspacing="1"><thead><tr><th>Query results obtained from the cache</th></tr></thead><tbody><tr>'; 940 $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>'; 941 $this->sql_report .= '<p style="text-align: center;">'; 942 $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 />'; 943 944 // Pad the start time to not interfere with page timing 945 $starttime += $time_db; 946 947 break; 948 949 default: 950 951 $this->_sql_report($mode, $query); 952 953 break; 954 } 955 956 return true; 957 } 958 959 /** 960 * Gets the estimated number of rows in a specified table. 961 * 962 * @param string $table_name Table name 963 * 964 * @return string Number of rows in $table_name. 965 * Prefixed with ~ if estimated (otherwise exact). 966 * 967 * @access public 968 */ 969 function get_estimated_row_count($table_name) 970 { 971 return $this->get_row_count($table_name); 972 } 973 974 /** 975 * Gets the exact number of rows in a specified table. 976 * 977 * @param string $table_name Table name 978 * 979 * @return string Exact number of rows in $table_name. 980 * 981 * @access public 982 */ 983 function get_row_count($table_name) 984 { 985 $sql = 'SELECT COUNT(*) AS rows_total 986 FROM ' . $this->sql_escape($table_name); 987 $result = $this->sql_query($sql); 988 $rows_total = $this->sql_fetchfield('rows_total'); 989 $this->sql_freeresult($result); 990 991 return $rows_total; 992 } 993 } 994 995 /** 996 * This variable holds the class name to use later 997 */ 998 $sql_db = (!empty($dbms)) ? 'dbal_' . basename($dbms) : 'dbal'; 999 1000 ?>
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 |