"TYPO3 4.0.1: typo3_src-4.0.1/typo3/sysext/adodb/adodb/adodb-perf.inc.php Source File", "datetime" => "Sat Dec 2 19:22:24 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>

adodb-perf.inc.php

00001 <?php
00002 /* 
00003 V4.90 8 June 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
00004   Released under both BSD license and Lesser GPL library license. 
00005   Whenever there is any discrepancy between the two licenses, 
00006   the BSD license will take precedence. See License.txt. 
00007   Set tabs to 4 for best viewing.
00008   
00009   Latest version is available at http://adodb.sourceforge.net
00010   
00011   Library for basic performance monitoring and tuning.
00012   
00013   My apologies if you see code mixed with presentation. The presentation suits
00014   my needs. If you want to separate code from presentation, be my guest. Patches
00015   are welcome.
00016   
00017 */
00018 
00019 if (!defined('ADODB_DIR')) include_once(dirname(__FILE__).'/adodb.inc.php');
00020 include_once(ADODB_DIR.'/tohtml.inc.php');
00021 
00022 define( 'ADODB_OPT_HIGH', 2);
00023 define( 'ADODB_OPT_LOW', 1);
00024 
00025 // returns in K the memory of current process, or 0 if not known
00026 function adodb_getmem()
00027 {
00028         if (function_exists('memory_get_usage'))
00029                 return (integer) ((memory_get_usage()+512)/1024);
00030         
00031         $pid = getmypid();
00032         
00033         if ( strncmp(strtoupper(PHP_OS),'WIN',3)==0) {
00034                 $output = array();
00035         
00036                 exec('tasklist /FI "PID eq ' . $pid. '" /FO LIST', $output); 
00037                 return substr($output[5], strpos($output[5], ':') + 1);
00038         } 
00039         
00040         /* Hopefully UNIX */
00041         exec("ps --pid $pid --no-headers -o%mem,size", $output);
00042         if (sizeof($output) == 0) return 0;
00043         
00044         $memarr = explode(' ',$output[0]);
00045         if (sizeof($memarr)>=2) return (integer) $memarr[1];
00046         
00047         return 0;
00048 }
00049 
00050 // avoids localization problems where , is used instead of .
00051 function adodb_round($n,$prec)
00052 {
00053         return number_format($n, $prec, '.', '');
00054 }
00055 
00056 /* return microtime value as a float */
00057 function adodb_microtime()
00058 {
00059         $t = microtime();
00060         $t = explode(' ',$t);
00061         return (float)$t[1]+ (float)$t[0];
00062 }
00063 
00064 /* sql code timing */
00065 function& adodb_log_sql(&$conn,$sql,$inputarr)
00066 {
00067         
00068     $perf_table = adodb_perf::table();
00069         $conn->fnExecute = false;
00070         $t0 = microtime();
00071         $rs =& $conn->Execute($sql,$inputarr);
00072         $t1 = microtime();
00073 
00074         if (!empty($conn->_logsql)) {
00075                 $conn->_logsql = false; // disable logsql error simulation
00076                 $dbT = $conn->databaseType;
00077                 
00078                 $a0 = split(' ',$t0);
00079                 $a0 = (float)$a0[1]+(float)$a0[0];
00080                 
00081                 $a1 = split(' ',$t1);
00082                 $a1 = (float)$a1[1]+(float)$a1[0];
00083                 
00084                 $time = $a1 - $a0;
00085         
00086                 if (!$rs) {
00087                         $errM = $conn->ErrorMsg();
00088                         $errN = $conn->ErrorNo();
00089                         $conn->lastInsID = 0;
00090                         $tracer = substr('ERROR: '.htmlspecialchars($errM),0,250);
00091                 } else {
00092                         $tracer = '';
00093                         $errM = '';
00094                         $errN = 0;
00095                         $dbg = $conn->debug;
00096                         $conn->debug = false;
00097                         if (!is_object($rs) || $rs->dataProvider == 'empty') 
00098                                 $conn->_affected = $conn->affected_rows(true);
00099                         $conn->lastInsID = @$conn->Insert_ID();
00100                         $conn->debug = $dbg;
00101                 }
00102                 if (isset($_SERVER['HTTP_HOST'])) {
00103                         $tracer .= '<br>'.$_SERVER['HTTP_HOST'];
00104                         if (isset($_SERVER['PHP_SELF'])) $tracer .= $_SERVER['PHP_SELF'];
00105                 } else 
00106                         if (isset($_SERVER['PHP_SELF'])) $tracer .= '<br>'.$_SERVER['PHP_SELF'];
00107                 //$tracer .= (string) adodb_backtrace(false);
00108                 
00109                 $tracer = (string) substr($tracer,0,500);
00110                 
00111                 if (is_array($inputarr)) {
00112                         if (is_array(reset($inputarr))) $params = 'Array sizeof='.sizeof($inputarr);
00113                         else {
00114                                 // Quote string parameters so we can see them in the
00115                                 // performance stats. This helps spot disabled indexes.
00116                                 $xar_params = $inputarr;
00117                                 foreach ($xar_params as $xar_param_key => $xar_param) {
00118                                         if (gettype($xar_param) == 'string')
00119                                         $xar_params[$xar_param_key] = '"' . $xar_param . '"';
00120                                 }
00121                                 $params = implode(', ', $xar_params);
00122                                 if (strlen($params) >= 3000) $params = substr($params, 0, 3000);
00123                         }
00124                 } else {
00125                         $params = '';
00126                 }
00127                 
00128                 if (is_array($sql)) $sql = $sql[0];
00129                 $arr = array('b'=>strlen($sql).'.'.crc32($sql),
00130                                         'c'=>substr($sql,0,3900), 'd'=>$params,'e'=>$tracer,'f'=>adodb_round($time,6));
00131                 //var_dump($arr);
00132                 $saved = $conn->debug;
00133                 $conn->debug = 0;
00134                 
00135                 $d = $conn->sysTimeStamp;
00136                 if (empty($d)) $d = date("'Y-m-d H:i:s'");
00137                 if ($conn->dataProvider == 'oci8' && $dbT != 'oci8po') {
00138                         $isql = "insert into $perf_table values($d,:b,:c,:d,:e,:f)";
00139                 } else if ($dbT == 'odbc_mssql' || $dbT == 'informix' || $dbT == 'odbtp') {
00140                         $timer = $arr['f'];
00141                         if ($dbT == 'informix') $sql2 = substr($sql2,0,230);
00142 
00143                         $sql1 = $conn->qstr($arr['b']);
00144                         $sql2 = $conn->qstr($arr['c']);
00145                         $params = $conn->qstr($arr['d']);
00146                         $tracer = $conn->qstr($arr['e']);
00147                         
00148                         $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values($d,$sql1,$sql2,$params,$tracer,$timer)";
00149                         if ($dbT == 'informix') $isql = str_replace(chr(10),' ',$isql);
00150                         $arr = false;
00151                 } else {
00152                         $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values( $d,?,?,?,?,?)";
00153                 }
00154 
00155                 $ok = $conn->Execute($isql,$arr);
00156                 $conn->debug = $saved;
00157                 
00158                 if ($ok) {
00159                         $conn->_logsql = true; 
00160                 } else {
00161                         $err2 = $conn->ErrorMsg();
00162                         $conn->_logsql = true; // enable logsql error simulation
00163                         $perf =& NewPerfMonitor($conn);
00164                         if ($perf) {
00165                                 if ($perf->CreateLogTable()) $ok = $conn->Execute($isql,$arr);
00166                         } else {
00167                                 $ok = $conn->Execute("create table $perf_table (
00168                                 created varchar(50),
00169                                 sql0 varchar(250), 
00170                                 sql1 varchar(4000),
00171                                 params varchar(3000),
00172                                 tracer varchar(500),
00173                                 timer decimal(16,6))");
00174                         }
00175                         if (!$ok) {
00176                                 ADOConnection::outp( "<p><b>LOGSQL Insert Failed</b>: $isql<br>$err2</p>");
00177                                 $conn->_logsql = false;
00178                         }
00179                 }
00180                 $conn->_errorMsg = $errM;
00181                 $conn->_errorCode = $errN;
00182         } 
00183         $conn->fnExecute = 'adodb_log_sql';
00184         return $rs;
00185 }
00186 
00187         
00188 /*
00189 The settings data structure is an associative array that database parameter per element.
00190 
00191 Each database parameter element in the array is itself an array consisting of:
00192 
00193 0: category code, used to group related db parameters
00194 1: either
00195         a. sql string to retrieve value, eg. "select value from v\$parameter where name='db_block_size'", 
00196         b. array holding sql string and field to look for, e.g. array('show variables','table_cache'),
00197         c. a string prefixed by =, then a PHP method of the class is invoked, 
00198                 e.g. to invoke $this->GetIndexValue(), set this array element to '=GetIndexValue',
00199 2: description of the database parameter
00200 */
00201 
00202 class adodb_perf {
00203         var $conn;
00204         var $color = '#F0F0F0';
00205         var $table = '<table border=1 bgcolor=white>';
00206         var $titles = '<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Description</b></td></tr>';
00207         var $warnRatio = 90;
00208         var $tablesSQL = false;
00209         var $cliFormat = "%32s => %s \r\n";
00210         var $sql1 = 'sql1';  // used for casting sql1 to text for mssql
00211         var $explain = true;
00212         var $helpurl = "<a href=http://phplens.com/adodb/reference.functions.fnexecute.and.fncacheexecute.properties.html#logsql>LogSQL help</a>";
00213         var $createTableSQL = false;
00214         var $maxLength = 2000;
00215         
00216     // Sets the tablename to be used            
00217     function table($newtable = false)
00218     {
00219         static $_table;
00220 
00221         if (!empty($newtable))  $_table = $newtable;
00222                 if (empty($_table)) $_table = 'adodb_logsql';
00223         return $_table;
00224     }
00225 
00226         // returns array with info to calculate CPU Load
00227         function _CPULoad()
00228         {
00229 /*
00230 
00231 cpu  524152 2662 2515228 336057010
00232 cpu0 264339 1408 1257951 168025827
00233 cpu1 259813 1254 1257277 168031181
00234 page 622307 25475680
00235 swap 24 1891
00236 intr 890153570 868093576 6 0 4 4 0 6 1 2 0 0 0 124 0 8098760 2 13961053 0 0 0 0 0 0 0 0 0 0 0 0 0 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
00237 disk_io: (3,0):(3144904,54369,610378,3090535,50936192) (3,1):(3630212,54097,633016,3576115,50951320)
00238 ctxt 66155838
00239 btime 1062315585
00240 processes 69293
00241 
00242 */
00243                 // Algorithm is taken from
00244                 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/example__obtaining_raw_performance_data.asp
00245                 if (strncmp(PHP_OS,'WIN',3)==0) {
00246                         if (PHP_VERSION == '5.0.0') return false;
00247                         if (PHP_VERSION == '5.0.1') return false;
00248                         if (PHP_VERSION == '5.0.2') return false;
00249                         if (PHP_VERSION == '5.0.3') return false;
00250                         if (PHP_VERSION == '4.3.10') return false; # see http://bugs.php.net/bug.php?id=31737
00251                         
00252                         @$c = new COM("WinMgmts:{impersonationLevel=impersonate}!Win32_PerfRawData_PerfOS_Processor.Name='_Total'");
00253                         if (!$c) return false;
00254                         
00255                         $info[0] = $c->PercentProcessorTime;
00256                         $info[1] = 0;
00257                         $info[2] = 0;
00258                         $info[3] = $c->TimeStamp_Sys100NS;
00259                         //print_r($info);
00260                         return $info;
00261                 }
00262                 
00263                 // Algorithm - Steve Blinch (BlitzAffe Online, http://www.blitzaffe.com)
00264                 $statfile = '/proc/stat';
00265                 if (!file_exists($statfile)) return false;
00266                 
00267                 $fd = fopen($statfile,"r");
00268                 if (!$fd) return false;
00269                 
00270                 $statinfo = explode("\n",fgets($fd, 1024));
00271                 fclose($fd);
00272                 foreach($statinfo as $line) {
00273                         $info = explode(" ",$line);
00274                         if($info[0]=="cpu") {
00275                                 array_shift($info);  // pop off "cpu"
00276                                 if(!$info[0]) array_shift($info); // pop off blank space (if any)
00277                                 return $info;
00278                         }
00279                 }
00280                 
00281                 return false;
00282                 
00283         }
00284         
00285         /* NOT IMPLEMENTED */
00286         function MemInfo()
00287         {
00288                 /*
00289 
00290         total:    used:    free:  shared: buffers:  cached:
00291 Mem:  1055289344 917299200 137990144        0 165437440 599773184
00292 Swap: 2146775040 11055104 2135719936
00293 MemTotal:      1030556 kB
00294 MemFree:        134756 kB
00295 MemShared:           0 kB
00296 Buffers:        161560 kB
00297 Cached:         581384 kB
00298 SwapCached:       4332 kB
00299 Active:         494468 kB
00300 Inact_dirty:    322856 kB
00301 Inact_clean:     24256 kB
00302 Inact_target:   168316 kB
00303 HighTotal:      131064 kB
00304 HighFree:         1024 kB
00305 LowTotal:       899492 kB
00306 LowFree:        133732 kB
00307 SwapTotal:     2096460 kB
00308 SwapFree:      2085664 kB
00309 Committed_AS:   348732 kB
00310                 */
00311         }
00312         
00313         
00314         /*
00315                 Remember that this is client load, not db server load!
00316         */
00317         var $_lastLoad;
00318         function CPULoad()
00319         {
00320                 $info = $this->_CPULoad();
00321                 if (!$info) return false;
00322                         
00323                 if (empty($this->_lastLoad)) {
00324                         sleep(1);
00325                         $this->_lastLoad = $info;
00326                         $info = $this->_CPULoad();
00327                 }
00328                 
00329                 $last = $this->_lastLoad;
00330                 $this->_lastLoad = $info;
00331                 
00332                 $d_user = $info[0] - $last[0];
00333                 $d_nice = $info[1] - $last[1];
00334                 $d_system = $info[2] - $last[2];
00335                 $d_idle = $info[3] - $last[3];
00336                 
00337                 //printf("Delta - User: %f  Nice: %f  System: %f  Idle: %f<br>",$d_user,$d_nice,$d_system,$d_idle);
00338 
00339                 if (strncmp(PHP_OS,'WIN',3)==0) {
00340                         if ($d_idle < 1) $d_idle = 1;
00341                         return 100*(1-$d_user/$d_idle);
00342                 }else {
00343                         $total=$d_user+$d_nice+$d_system+$d_idle;
00344                         if ($total<1) $total=1;
00345                         return 100*($d_user+$d_nice+$d_system)/$total; 
00346                 }
00347         }
00348         
00349         function Tracer($sql)
00350         {
00351         $perf_table = adodb_perf::table();
00352                 $saveE = $this->conn->fnExecute;
00353                 $this->conn->fnExecute = false;
00354                 
00355                 global $ADODB_FETCH_MODE;
00356                 $save = $ADODB_FETCH_MODE;
00357                 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00358                 if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
00359                                 
00360                 $sqlq = $this->conn->qstr($sql);
00361                 $arr = $this->conn->GetArray(
00362 "select count(*),tracer 
00363         from $perf_table where sql1=$sqlq 
00364         group by tracer
00365         order by 1 desc");
00366                 $s = '';
00367                 if ($arr) {
00368                         $s .= '<h3>Scripts Affected</h3>';
00369                         foreach($arr as $k) {
00370                                 $s .= sprintf("%4d",$k[0]).' &nbsp; '.strip_tags($k[1]).'<br>';
00371                         }
00372                 }
00373                 
00374                 if (isset($savem)) $this->conn->SetFetchMode($savem);
00375                 $ADODB_CACHE_MODE = $save;
00376                 $this->conn->fnExecute = $saveE;
00377                 return $s;
00378         }
00379 
00380         /* 
00381                 Explain Plan for $sql.
00382                 If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the 
00383                         actual sql.
00384         */
00385         function Explain($sql,$partial=false)
00386         {       
00387                 return false;
00388         }
00389         
00390         function InvalidSQL($numsql = 10)
00391         {
00392         
00393                 if (isset($_GET['sql'])) return;
00394                 $s = '<h3>Invalid SQL</h3>';
00395                 $saveE = $this->conn->fnExecute;
00396                 $this->conn->fnExecute = false;
00397         $perf_table = adodb_perf::table();
00398                 $rs =& $this->conn->SelectLimit("select distinct count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql);
00399                 $this->conn->fnExecute = $saveE;
00400                 if ($rs) {
00401                         $s .= rs2html($rs,false,false,false,false);
00402                 } else
00403                         return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
00404                 
00405                 return $s;
00406         }
00407 
00408         
00409         /*
00410                 This script identifies the longest running SQL
00411         */      
00412         function _SuspiciousSQL($numsql = 10)
00413         {
00414                 global $ADODB_FETCH_MODE;
00415                 
00416             $perf_table = adodb_perf::table();
00417                         $saveE = $this->conn->fnExecute;
00418                         $this->conn->fnExecute = false;
00419                         
00420                         if (isset($_GET['exps']) && isset($_GET['sql'])) {
00421                                 $partial = !empty($_GET['part']);
00422                                 echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
00423                         }
00424                         
00425                         if (isset($_GET['sql'])) return;
00426                         $sql1 = $this->sql1;
00427                         
00428                         $save = $ADODB_FETCH_MODE;
00429                         $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00430                         if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
00431                         //$this->conn->debug=1;
00432                         $rs =& $this->conn->SelectLimit(
00433                         "select avg(timer) as avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
00434                                 from $perf_table
00435                                 where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT')
00436                                 and (tracer is null or tracer not like 'ERROR:%')
00437                                 group by sql1
00438                                 order by 1 desc",$numsql);
00439                         if (isset($savem)) $this->conn->SetFetchMode($savem);
00440                         $ADODB_FETCH_MODE = $save;
00441                         $this->conn->fnExecute = $saveE;
00442                         
00443                         if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
00444                         $s = "<h3>Suspicious SQL</h3>
00445 <font size=1>The following SQL have high average execution times</font><br>
00446 <table border=1 bgcolor=white><tr><td><b>Avg Time</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
00447                         $max = $this->maxLength;
00448                         while (!$rs->EOF) {
00449                                 $sql = $rs->fields[1];
00450                                 $raw = urlencode($sql);
00451                                 if (strlen($raw)>$max-100) {
00452                                         $sql2 = substr($sql,0,$max-500);
00453                                         $raw = urlencode($sql2).'&part='.crc32($sql);
00454                                 }
00455                                 $prefix = "<a target=sql".rand()." href=\"?hidem=1&exps=1&sql=".$raw."&x#explain\">";
00456                                 $suffix = "</a>";
00457                                 if ($this->explain == false || strlen($prefix)>$max) {
00458                                         $suffix = ' ... <i>String too long for GET parameter: '.strlen($prefix).'</i>';
00459                                         $prefix = '';
00460                                 }
00461                                 $s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
00462                                         "<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
00463                                 $rs->MoveNext();
00464                         }
00465                         return $s."</table>";
00466                 
00467         }
00468         
00469         function CheckMemory()
00470         {
00471                 return '';
00472         }
00473         
00474         
00475         function SuspiciousSQL($numsql=10)
00476         {
00477                 return adodb_perf::_SuspiciousSQL($numsql);
00478         }
00479 
00480         function ExpensiveSQL($numsql=10)
00481         {
00482                 return adodb_perf::_ExpensiveSQL($numsql);
00483         }
00484 
00485         
00486         /*
00487                 This reports the percentage of load on the instance due to the most 
00488                 expensive few SQL statements. Tuning these statements can often 
00489                 make huge improvements in overall system performance. 
00490         */
00491         function _ExpensiveSQL($numsql = 10)
00492         {
00493                 global $ADODB_FETCH_MODE;
00494                 
00495             $perf_table = adodb_perf::table();
00496                         $saveE = $this->conn->fnExecute;
00497                         $this->conn->fnExecute = false;
00498                         
00499                         if (isset($_GET['expe']) && isset($_GET['sql'])) {
00500                                 $partial = !empty($_GET['part']);
00501                                 echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
00502                         }
00503                         
00504                         if (isset($_GET['sql'])) return;
00505                         
00506                         $sql1 = $this->sql1;
00507                         $save = $ADODB_FETCH_MODE;
00508                         $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00509                         if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
00510                         
00511                         $rs =& $this->conn->SelectLimit(
00512                         "select sum(timer) as total,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
00513                                 from $perf_table
00514                                 where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5))  not in ('DROP ','INSER','COMMI','CREAT')
00515                                 and (tracer is null or tracer not like 'ERROR:%')
00516                                 group by sql1
00517                                 having count(*)>1
00518                                 order by 1 desc",$numsql);
00519                         if (isset($savem)) $this->conn->SetFetchMode($savem);
00520                         $this->conn->fnExecute = $saveE;
00521                         $ADODB_FETCH_MODE = $save;
00522                         if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
00523                         $s = "<h3>Expensive SQL</h3>
00524 <font size=1>Tuning the following SQL could reduce the server load substantially</font><br>
00525 <table border=1 bgcolor=white><tr><td><b>Load</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
00526                         $max = $this->maxLength;
00527                         while (!$rs->EOF) {
00528                                 $sql = $rs->fields[1];
00529                                 $raw = urlencode($sql);
00530                                 if (strlen($raw)>$max-100) {
00531                                         $sql2 = substr($sql,0,$max-500);
00532                                         $raw = urlencode($sql2).'&part='.crc32($sql);
00533                                 }
00534                                 $prefix = "<a target=sqle".rand()." href=\"?hidem=1&expe=1&sql=".$raw."&x#explain\">";
00535                                 $suffix = "</a>";
00536                                 if($this->explain == false || strlen($prefix>$max)) {
00537                                         $prefix = '';
00538                                         $suffix = '';
00539                                 }
00540                                 $s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
00541                                         "<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
00542                                 $rs->MoveNext();
00543                         }
00544                         return $s."</table>";
00545         }
00546         
00547         /*
00548                 Raw function to return parameter value from $settings.
00549         */
00550         function DBParameter($param)
00551         {
00552                 if (empty($this->settings[$param])) return false;
00553                 $sql = $this->settings[$param][1];
00554                 return $this->_DBParameter($sql);
00555         }
00556         
00557         /*
00558                 Raw function returning array of poll paramters
00559         */
00560         function &PollParameters()
00561         {
00562                 $arr[0] = (float)$this->DBParameter('data cache hit ratio');
00563                 $arr[1] = (float)$this->DBParameter('data reads');
00564                 $arr[2] = (float)$this->DBParameter('data writes');
00565                 $arr[3] = (integer) $this->DBParameter('current connections');
00566                 return $arr;
00567         }
00568         
00569         /*
00570                 Low-level Get Database Parameter
00571         */
00572         function _DBParameter($sql)
00573         {
00574                 $savelog = $this->conn->LogSQL(false);
00575                 if (is_array($sql)) {
00576                 global $ADODB_FETCH_MODE;
00577                 
00578                         $sql1 = $sql[0];
00579                         $key = $sql[1];
00580                         if (sizeof($sql)>2) $pos = $sql[2];
00581                         else $pos = 1;
00582                         if (sizeof($sql)>3) $coef = $sql[3];
00583                         else $coef = false;
00584                         $ret = false;
00585                         $save = $ADODB_FETCH_MODE;
00586                         $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00587                         if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
00588                         
00589                         $rs = $this->conn->Execute($sql1);
00590                         
00591                         if (isset($savem)) $this->conn->SetFetchMode($savem);
00592                         $ADODB_FETCH_MODE = $save;
00593                         if ($rs) {
00594                                 while (!$rs->EOF) {
00595                                         $keyf = reset($rs->fields);
00596                                         if (trim($keyf) == $key) {
00597                                                 $ret = $rs->fields[$pos];
00598                                                 if ($coef) $ret *= $coef;
00599                                                 break;
00600                                         }
00601                                         $rs->MoveNext();
00602                                 }
00603                                 $rs->Close();
00604                         }
00605                         $this->conn->LogSQL($savelog);
00606                         return $ret;
00607                 } else {
00608                         if (strncmp($sql,'=',1) == 0) {
00609                                 $fn = substr($sql,1);
00610                                 return $this->$fn();
00611                         }
00612                         $sql = str_replace('$DATABASE',$this->conn->database,$sql);
00613                         $ret = $this->conn->GetOne($sql);
00614                         $this->conn->LogSQL($savelog);
00615                         
00616                         return $ret;
00617                 }
00618         }
00619         
00620         /*
00621                 Warn if cache ratio falls below threshold. Displayed in "Description" column.
00622         */
00623         function WarnCacheRatio($val)
00624         {
00625                 if ($val < $this->warnRatio) 
00626                          return '<font color=red><b>Cache ratio should be at least '.$this->warnRatio.'%</b></font>';
00627                 else return '';
00628         }
00629         
00630         /***********************************************************************************************/
00631         //                                    HIGH LEVEL UI FUNCTIONS
00632         /***********************************************************************************************/
00633 
00634         
00635         function UI($pollsecs=5)
00636         {
00637         
00638     $perf_table = adodb_perf::table();
00639         $conn = $this->conn;
00640         
00641         $app = $conn->host;
00642         if ($conn->host && $conn->database) $app .= ', db=';
00643         $app .= $conn->database;
00644         
00645         if ($app) $app .= ', ';
00646         $savelog = $this->conn->LogSQL(false);  
00647         $info = $conn->ServerInfo();
00648         if (isset($_GET['clearsql'])) {
00649                 $this->conn->Execute("delete from $perf_table");
00650         }
00651         $this->conn->LogSQL($savelog);
00652         
00653         // magic quotes
00654         
00655         if (isset($_GET['sql']) && get_magic_quotes_gpc()) {
00656                 $_GET['sql'] = $_GET['sql'] = str_replace(array("\\'",'\"'),array("'",'"'),$_GET['sql']);
00657         }
00658         
00659         if (!isset($_SESSION['ADODB_PERF_SQL'])) $nsql = $_SESSION['ADODB_PERF_SQL'] = 10;
00660         else  $nsql = $_SESSION['ADODB_PERF_SQL'];
00661         
00662         $app .= $info['description'];
00663         
00664         
00665         if (isset($_GET['do'])) $do = $_GET['do'];
00666         else if (isset($_POST['do'])) $do = $_POST['do'];
00667          else if (isset($_GET['sql'])) $do = 'viewsql';
00668          else $do = 'stats';
00669          
00670         if (isset($_GET['nsql'])) {
00671                 if ($_GET['nsql'] > 0) $nsql = $_SESSION['ADODB_PERF_SQL'] = (integer) $_GET['nsql'];
00672         }
00673         echo "<title>ADOdb Performance Monitor on $app</title><body bgcolor=white>";
00674         if ($do == 'viewsql') $form = "<td><form># SQL:<input type=hidden value=viewsql name=do> <input type=text size=4 name=nsql value=$nsql><input type=submit value=Go></td></form>";
00675         else $form = "<td>&nbsp;</td>";
00676         
00677         $allowsql = !defined('ADODB_PERF_NO_RUN_SQL');
00678         
00679         if  (empty($_GET['hidem']))
00680         echo "<table border=1 width=100% bgcolor=lightyellow><tr><td colspan=2>
00681         <b><a href=http://adodb.sourceforge.net/?perf=1>ADOdb</a> Performance Monitor</b> <font size=1>for $app</font></tr><tr><td>
00682         <a href=?do=stats><b>Performance Stats</b></a> &nbsp; <a href=?do=viewsql><b>View SQL</b></a>
00683          &nbsp; <a href=?do=tables><b>View Tables</b></a> &nbsp; <a href=?do=poll><b>Poll Stats</b></a>",
00684          $allowsql ? ' &nbsp; <a href=?do=dosql><b>Run SQL</b></a>' : '',
00685          "$form",
00686          "</tr></table>";
00687 
00688          
00689                 switch ($do) {
00690                 default:
00691                 case 'stats':
00692                         echo $this->HealthCheck();
00693                         //$this->conn->debug=1;
00694                         echo $this->CheckMemory();
00695                         break;
00696                 case 'poll':
00697                         echo "<iframe width=720 height=80% 
00698                                 src=\"{$_SERVER['PHP_SELF']}?do=poll2&hidem=1\"></iframe>";
00699                         break;
00700                 case 'poll2':
00701                         echo "<pre>";
00702                         $this->Poll($pollsecs);
00703                         break;
00704                 
00705                 case 'dosql':
00706                         if (!$allowsql) break;
00707                         
00708                         $this->DoSQLForm();
00709                         break;
00710                 case 'viewsql':
00711                         if (empty($_GET['hidem']))
00712                                 echo "&nbsp; <a href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>";
00713                         echo($this->SuspiciousSQL($nsql));
00714                         echo($this->ExpensiveSQL($nsql));
00715                         echo($this->InvalidSQL($nsql));
00716                         break;
00717                 case 'tables': 
00718                         echo $this->Tables(); break;
00719                 }
00720                 global $ADODB_vers;
00721                 echo "<p><div align=center><font size=1>$ADODB_vers Sponsored by <a href=http://phplens.com/>phpLens</a></font></div>";
00722         }
00723         
00724         /*
00725                 Runs in infinite loop, returning real-time statistics
00726         */
00727         function Poll($secs=5)
00728         {
00729                 $this->conn->fnExecute = false;
00730                 //$this->conn->debug=1;
00731                 if ($secs <= 1) $secs = 1;
00732                 echo "Accumulating statistics, every $secs seconds...\n";flush();
00733                 $arro =& $this->PollParameters();
00734                 $cnt = 0;
00735                 set_time_limit(0);
00736                 sleep($secs);
00737                 while (1) {
00738 
00739                         $arr =& $this->PollParameters();
00740                         
00741                         $hits   = sprintf('%2.2f',$arr[0]);
00742                         $reads  = sprintf('%12.4f',($arr[1]-$arro[1])/$secs);
00743                         $writes = sprintf('%12.4f',($arr[2]-$arro[2])/$secs);
00744                         $sess = sprintf('%5d',$arr[3]);
00745                         
00746                         $load = $this->CPULoad();
00747                         if ($load !== false) {
00748                                 $oslabel = 'WS-CPU%';
00749                                 $osval = sprintf(" %2.1f  ",(float) $load);
00750                         }else {
00751                                 $oslabel = '';
00752                                 $osval = '';
00753                         }
00754                         if ($cnt % 10 == 0) echo " Time   ".$oslabel."   Hit%   Sess           Reads/s          Writes/s\n"; 
00755                         $cnt += 1;
00756                         echo date('H:i:s').'  '.$osval."$hits  $sess $reads $writes\n";
00757                         flush();
00758                         
00759                         if (connection_aborted()) return;
00760                         
00761                         sleep($secs);
00762                         $arro = $arr;
00763                 }
00764         }
00765         
00766         /*
00767                 Returns basic health check in a command line interface
00768         */
00769         function HealthCheckCLI()
00770         {
00771                 return $this->HealthCheck(true);
00772         }
00773         
00774                 
00775         /*
00776                 Returns basic health check as HTML
00777         */
00778         function HealthCheck($cli=false)
00779         {
00780                 $saveE = $this->conn->fnExecute;
00781                 $this->conn->fnExecute = false; 
00782                 if ($cli) $html = '';
00783                 else $html = $this->table.'<tr><td colspan=3><h3>'.$this->conn->databaseType.'</h3></td></tr>'.$this->titles;
00784                 
00785                 $oldc = false;
00786                 $bgc = '';
00787                 foreach($this->settings as $name => $arr) {
00788                         if ($arr === false) break;
00789                         
00790                         if (!is_string($name)) {
00791                                 if ($cli) $html .= " -- $arr -- \n";
00792                                 else $html .= "<tr bgcolor=$this->color><td colspan=3><i>$arr</i> &nbsp;</td></tr>";
00793                                 continue;
00794                         }
00795                         
00796                         if (!is_array($arr)) break;
00797                         $category = $arr[0];
00798                         $how = $arr[1];
00799                         if (sizeof($arr)>2) $desc = $arr[2];
00800                         else $desc = ' &nbsp; ';
00801                         
00802                         
00803                         if ($category == 'HIDE') continue;
00804                         
00805                         $val = $this->_DBParameter($how);
00806                         
00807                         if ($desc && strncmp($desc,"=",1) === 0) {
00808                                 $fn = substr($desc,1);
00809                                 $desc = $this->$fn($val);
00810                         }
00811                         
00812                         if ($val === false) {
00813                                 $m = $this->conn->ErrorMsg();
00814                                 $val = "Error: $m"; 
00815                         } else {
00816                                 if (is_numeric($val) && $val >= 256*1024) {
00817                                         if ($val % (1024*1024) == 0) {
00818                                                 $val /= (1024*1024);
00819                                                 $val .= 'M';
00820                                         } else if ($val % 1024 == 0) {
00821                                                 $val /= 1024;
00822                                                 $val .= 'K';
00823                                         }
00824                                         //$val = htmlspecialchars($val);
00825                                 }
00826                         }
00827                         if ($category != $oldc) {
00828                                 $oldc = $category;
00829                                 //$bgc = ($bgc == ' bgcolor='.$this->color) ? ' bgcolor=white' : ' bgcolor='.$this->color;
00830                         }
00831                         if (strlen($desc)==0) $desc = '&nbsp;';
00832                         if (strlen($val)==0) $val = '&nbsp;';
00833                         if ($cli) {
00834                                 $html  .= str_replace('&nbsp;','',sprintf($this->cliFormat,strip_tags($name),strip_tags($val),strip_tags($desc)));
00835                                 
00836                         }else {
00837                                 $html .= "<tr$bgc><td>".$name.'</td><td>'.$val.'</td><td>'.$desc."</td></tr>\n";
00838                         }
00839                 }
00840                 
00841                 if (!$cli) $html .= "</table>\n";
00842                 $this->conn->fnExecute = $saveE;
00843                         
00844                 return $html;   
00845         }
00846         
00847         function Tables($orderby='1')
00848         {
00849                 if (!$this->tablesSQL) return false;
00850                 
00851                 $savelog = $this->conn->LogSQL(false);
00852                 $rs = $this->conn->Execute($this->tablesSQL.' order by '.$orderby);
00853                 $this->conn->LogSQL($savelog);
00854                 $html = rs2html($rs,false,false,false,false);
00855                 return $html;
00856         }
00857         
00858 
00859         function CreateLogTable()
00860         {
00861                 if (!$this->createTableSQL) return false;
00862                 
00863                 $table = $this->table();
00864                 $sql = str_replace('adodb_logsql',$table,$this->createTableSQL);
00865                 
00866                 $savelog = $this->conn->LogSQL(false);
00867                 $ok = $this->conn->Execute($sql);
00868                 $this->conn->LogSQL($savelog);
00869                 return ($ok) ? true : false;
00870         }
00871         
00872         function DoSQLForm()
00873         {
00874         
00875                 
00876                 $PHP_SELF = $_SERVER['PHP_SELF'];
00877                 $sql = isset($_REQUEST['sql']) ? $_REQUEST['sql'] : '';
00878 
00879                 if (isset($_SESSION['phplens_sqlrows'])) $rows = $_SESSION['phplens_sqlrows'];
00880                 else $rows = 3;
00881                 
00882                 if (isset($_REQUEST['SMALLER'])) {
00883                         $rows /= 2;
00884                         if ($rows < 3) $rows = 3;
00885                         $_SESSION['phplens_sqlrows'] = $rows;
00886                 }
00887                 if (isset($_REQUEST['BIGGER'])) {
00888                         $rows *= 2;
00889                         $_SESSION['phplens_sqlrows'] = $rows;
00890                 }
00891                 
00892 ?>
00893 
00894 <form method="POST" action="<?php echo $PHP_SELF ?>">
00895 <table><tr>
00896 <td> Form size: <input type="submit" value=" &lt; " name="SMALLER"><input type="submit" value=" &gt; &gt; " name="BIGGER">
00897 </td>
00898 <td align=right>
00899 <input type="submit" value=" Run SQL Below " name="RUN"><input type=hidden name=do value=dosql>
00900 </td></tr>
00901   <tr>
00902   <td colspan=2><textarea rows=<?php print $rows; ?> name="sql" cols="80"><?php print htmlspecialchars($sql) ?></textarea>
00903   </td>
00904   </tr>
00905  </table>
00906 </form>
00907 
00908 <?php
00909                 if (!isset($_REQUEST['sql'])) return;
00910                 
00911                 $sql = $this->undomq(trim($sql));
00912                 if (substr($sql,strlen($sql)-1) === ';') {
00913                         $print = true;
00914                         $sqla = $this->SplitSQL($sql);
00915                 } else  {
00916                         $print = false;
00917                         $sqla = array($sql);
00918                 }
00919                 foreach($sqla as $sqls) {
00920 
00921                         if (!$sqls) continue;
00922                         
00923                         if ($print) {
00924                                 print "<p>".htmlspecialchars($sqls)."</p>";
00925                                 flush();
00926                         }
00927                         $savelog = $this->conn->LogSQL(false);
00928                         $rs = $this->conn->Execute($sqls);
00929                         $this->conn->LogSQL($savelog);
00930                         if ($rs && is_object($rs) && !$rs->EOF) {
00931                                 rs2html($rs);
00932                                 while ($rs->NextRecordSet()) {
00933                                         print "<table width=98% bgcolor=#C0C0FF><tr><td>&nbsp;</td></tr></table>";
00934                                         rs2html($rs);
00935                                 }
00936                         } else {
00937                                 $e1 = (integer) $this->conn->ErrorNo();
00938                                 $e2 = $this->conn->ErrorMsg();
00939                                 if (($e1) || ($e2)) {
00940                                         if (empty($e1)) $e1 = '-1'; // postgresql fix
00941                                         print ' &nbsp; '.$e1.': '.$e2;
00942                                 } else {
00943                                         print "<p>No Recordset returned<br></p>";
00944                                 }
00945                         }
00946                 } // foreach
00947         }
00948         
00949         function SplitSQL($sql)
00950         {
00951                 $arr = explode(';',$sql);
00952                 return $arr;
00953         }
00954         
00955         function undomq($m) 
00956         {
00957         if (get_magic_quotes_gpc()) {
00958                 // undo the damage
00959                 $m = str_replace('\\\\','\\',$m);
00960                 $m = str_replace('\"','"',$m);
00961                 $m = str_replace('\\\'','\'',$m);
00962         }
00963         return $m;
00964 }
00965 
00966     
00967    /************************************************************************/
00968    
00992     function OptimizeTables()
00993     {
00994         $args = func_get_args();
00995         $numArgs = func_num_args();
00996         
00997         if ( $numArgs == 0) return false;
00998         
00999         $mode = ADODB_OPT_LOW; 
01000         $lastArg = $args[ $numArgs - 1];
01001         if ( !is_string($lastArg)) {
01002             $mode = $lastArg;
01003             unset( $args[ $numArgs - 1]);
01004         }
01005         
01006         foreach( $args as $table) {
01007             $this->optimizeTable( $table, $mode);
01008         }
01009         }
01010 
01023     function OptimizeTable( $table, $mode = ADODB_OPT_LOW) 
01024     {
01025         ADOConnection::outp( sprintf( "<p>%s: '%s' not implemented for driver '%s'</p>", __CLASS__, __FUNCTION__, $this->conn->databaseType));
01026         return false;
01027     }
01028     
01037     function optimizeDatabase() 
01038     {
01039         $conn = $this->conn;
01040         if ( !$conn) return false;
01041         
01042         $tables = $conn->MetaTables( 'TABLES');
01043         if ( !$tables ) return false;
01044 
01045         foreach( $tables as $table) {
01046             if ( !$this->optimizeTable( $table)) {
01047                 return false;
01048             }
01049         }
01050       
01051         return true;
01052     }
01053     // end hack 
01054 }
01055 
01056 ?>