oxdebugdb.php

Go to the documentation of this file.
00001 <?php
00002 
00003 
00008 class oxDebugDb
00009 {
00010 
00011     private static $_aSkipSqls = array();
00012 
00013     protected static function _skipWhiteSpace($str){
00014         return str_replace(array(' ', "\t", "\r", "\n"), '', $str);
00015     }
00016 
00017     protected static function _isSkipped($sSql){
00018         if (!count(self::$_aSkipSqls)) {
00019             $file = file_get_contents(realpath(dirname(__FILE__).'/..').'/oxdebugdb_skipped.sql');
00020             $m = explode('-- -- ENTRY END', $file);
00021             foreach ($m as $n) {
00022                 $n = self::_skipWhiteSpace($n);
00023                 if ($n)
00024                     self::$_aSkipSqls[md5($n)] = true;
00025             }
00026         }
00027         $checkTpl = md5(self::_skipWhiteSpace(self::getSqlTemplate($sSql)));
00028         $check = md5(self::_skipWhiteSpace($sSql));
00029         return self::$_aSkipSqls[$check] || self::$_aSkipSqls[$checkTpl];
00030     }
00031 
00037     public function getWarnings()
00038     {
00039         $aWarnings = array();
00040         $aHistory = array();
00041         $oDb = oxDb::getDb();
00042         $_lastDbgState = $oDb->LogSQL( false );
00043         $rs = $oDb->Execute("select sql0, sql1, tracer from adodb_logsql order by created limit 5000");
00044         if ($rs != false && $rs->recordCount() > 0) {
00045             $_lastRecord = null;
00046             while (!$rs->EOF) {
00047                 $sId  = $rs->fields[0];
00048                 $sSql = $rs->fields[1];
00049 
00050                 if (!self::_isSkipped($sSql)) {
00051                     if ($this->_checkMissingKeys($sSql)) {
00052                         $aWarnings['MissingKeys'][$sId] = true;
00053 // debug: echo "<li> <pre>".self::getSqlTemplate($sSql)." </pre><br>";
00054                     }
00055                 }
00056 
00057                 // multiple executed single statements
00058                 if ($_lastRecord && $this->_checkMess($sSql,$_lastRecord[1])) {
00059                     // sql0 matches, also, this is exactly following statement: MESS?
00060                     $aWarnings['MESS'][$sId] = true;
00061                     $aWarnings['MESS'][$_lastRecord[0]] = true;
00062                 }
00063 
00064                 foreach ($aHistory as $aHistItem) {
00065                     if ($this->_checkMess($sSql,$aHistItem[1])) {
00066                         // sql0 matches, also, this is exactly following statement: MESS?
00067                         $aWarnings['MESS_ALL'][$sId] = true;
00068                         $aWarnings['MESS_ALL'][$aHistItem[0]] = true;
00069                     }
00070                 }
00071 
00072                 $aHistory[] = $_lastRecord = $rs->fields;
00073 /*
00074                 if (preg_match('/select[^\*]*(?<!(from))\*.*?(?<!(from))from/im', $sSql)) {
00075                     $aWarnings['Select fields not strict'][$sId] = true;
00076                 }*/
00077                 $rs->moveNext();
00078             }
00079         }
00080         $aWarnings = $this->_generateWarningsResult($aWarnings);
00081         $this->_logToFile($aWarnings);
00082         $oDb->LogSQL( $_lastDbgState );
00083         return $aWarnings;
00084     }
00085 
00091     protected function _generateWarningsResult($aInput)
00092     {
00093         $aOutput = array();
00094         $oDb = oxDb::getDb();
00095         foreach ($aInput as $fnc => $aWarnings) {
00096             $ids = implode("','", array_keys($aWarnings));
00097             $rs = $oDb->Execute("select sql1, timer, tracer from adodb_logsql where sql0 in ('$ids')");
00098             if ($rs != false && $rs->recordCount() > 0) {
00099                 while (!$rs->EOF) {
00100                     $aOutputEntry = array();
00101                     $aOutputEntry['check'] = $fnc;
00102                     $aOutputEntry['sql'] = $rs->fields[0];
00103                     $aOutputEntry['time'] = $rs->fields[1];
00104                     $aOutputEntry['trace'] = $rs->fields[2];
00105                     $aOutput[] = $aOutputEntry;
00106                     $rs->moveNext();
00107                 }
00108             }
00109         }
00110         return $aOutput;
00111     }
00112 
00119     protected function _checkMissingKeys($sSql)
00120     {
00121         if (strpos(strtolower(trim($sSql)), 'select ') !== 0)
00122             return false;
00123 
00124         $oDb = oxDb::getDb(true);
00125         $rs = $oDb->Execute("explain $sSql");
00126         if ($rs != false && $rs->recordCount() > 0) {
00127             while (!$rs->EOF) {
00128                 if ($this->_missingKeysChecker($rs->fields))
00129                     return true;
00130                 $rs->moveNext();
00131             }
00132         }
00133         return false;
00134     }
00135 
00142     private function _missingKeysChecker($aExplain)
00143     {
00144 
00145         if ($aExplain['type'] == 'system') {
00146             return false;
00147         }
00148 
00149         if ($aExplain['key'] === null)
00150             return true;
00151 
00152         if (strpos($aExplain['type'], 'range'))
00153             return true;
00154         if (strpos($aExplain['type'], 'index'))
00155             return true;
00156         if (strpos($aExplain['type'], 'ALL'))
00157             return true;
00158 
00159         if (strpos($aExplain['Extra'], 'filesort')) {
00160             if (strpos($aExplain['ref'], 'const') === false)
00161                 return true;
00162         }
00163         if (strpos($aExplain['Extra'], 'temporary'))
00164             return true;
00165 
00166         return false;
00167     }
00168 
00176     protected function _checkMess($s1, $s2)
00177     {
00178         if (strpos(strtolower(trim($s1)), 'select ') !== 0)
00179             return false;
00180         if (strpos(strtolower(trim($s2)), 'select ') !== 0)
00181             return false;
00182 
00183         // strip from values
00184         $s1 = self::getSqlTemplate($s1);
00185         $s2 = self::getSqlTemplate($s2);
00186 
00187         if (!strcmp($s1, $s2)) {
00188             return true;
00189         }
00190 
00191         return false;
00192     }
00193 
00200     protected static function getSqlTemplate($sSql) {
00201         $sSql = preg_replace("/'.*?(?<!\\\\)'/", "'#VALUE#'", $sSql);
00202         $sSql = preg_replace('/".*?(?<!\\\\)"/', '"#VALUE#"', $sSql);
00203         $sSql = preg_replace('/[0-9]/', '#NUMVALUE#', $sSql);
00204         return $sSql;
00205     }
00206 
00207 
00208 
00212     protected function _logToFile($aWarnings)
00213     {
00214         $s = "\n\n\n\n\n\n-- ".date("m-d  H:i:s")." --\n\n";
00215         foreach ($aWarnings as $w)
00216         {
00217             $s .= "{$w['check']}: {$w['time']} - ".htmlentities($w['sql'])."\n\n";
00218             $s .= $w['trace']."\n\n\n\n";
00219         }
00220         $f = fopen(realpath(dirname(__FILE__).'/..').'/oxdebugdb.txt', "a+");
00221         if (!$f)
00222             return;
00223         fwrite($f, $s);
00224         fclose($f);
00225     }
00226 }

Generated on Thu Dec 4 12:04:56 2008 for OXID eShop CE by  doxygen 1.5.5