From e95ab08945c3bb99627adcb5998e5e389084a0f0 Mon Sep 17 00:00:00 2001 From: DSB Date: Mon, 20 Jun 2011 13:39:03 +0000 Subject: [PATCH] SQl-Parser: - changes and fixes for parsing statements - QA SQl-Browser / SQL-Box: - added semicolon to table select box --- application/controllers/SqlController.php | 5 +- .../views/scripts/sql/sqlbox/sqlbox.phtml | 2 +- library/Msd/Html.php | 7 +- library/Msd/Sql/Object.php | 95 ++++++++++++++----- library/Msd/Sql/Parser.php | 25 ++--- library/Msd/Sql/Parser/Statement/Alter.php | 1 - library/Msd/Sql/Parser/Statement/Comment.php | 13 +-- library/Msd/Sql/Parser/Statement/Create.php | 1 - library/Msd/Sql/Parser/Statement/Drop.php | 1 - library/Msd/Sql/Parser/Statement/Insert.php | 1 - library/Msd/Sql/Parser/Statement/Lock.php | 1 - library/Msd/Sql/Parser/Statement/Select.php | 1 - library/Msd/Sql/Parser/Statement/Unlock.php | 1 - 13 files changed, 98 insertions(+), 56 deletions(-) diff --git a/application/controllers/SqlController.php b/application/controllers/SqlController.php index 8a9a660..f501fb3 100644 --- a/application/controllers/SqlController.php +++ b/application/controllers/SqlController.php @@ -394,12 +394,11 @@ class SqlController extends Zend_Controller_Action if ($sqlObject->hasErrors()) { $this->view->errorMessage = implode('
', $sqlObject->getErrors()); } - //echo $parser->getDebugOutput(); $statements = $parser->getParsedStatements(); foreach ($statements as $statement) { - echo "
- ".$statement; + //echo "
Extracted statement: ".$statement; try { - $res = array(); //$this->_db->query($statement, Msd_Db::ARRAY_ASSOC); + $res = $this->_db->query($statement, Msd_Db::ARRAY_ASSOC); $this->view->resultset = $res; } catch (Exception $e) { $this->view->errorMessage = $e->getMessage(); diff --git a/application/views/scripts/sql/sqlbox/sqlbox.phtml b/application/views/scripts/sql/sqlbox/sqlbox.phtml index cc25fa3..2313a00 100644 --- a/application/views/scripts/sql/sqlbox/sqlbox.phtml +++ b/application/views/scripts/sql/sqlbox/sqlbox.phtml @@ -43,7 +43,7 @@ if (isset($this->errorMessage)) { function setShowTableQuery() { query = $('#selectTable').attr('value'); - query = 'SELECT * FROM `' + query + '`'; + query = 'SELECT * FROM `' + query + '`;'; $('#sqltextarea').val(query); $('#myForm').submit(); } diff --git a/library/Msd/Html.php b/library/Msd/Html.php index a9d42bc..b21724e 100644 --- a/library/Msd/Html.php +++ b/library/Msd/Html.php @@ -44,12 +44,11 @@ class Msd_Html * Returns a new array containing the different prefixes. Used for building * filter select boxes (e.g. sqlserver/show.variables). * - * @param array $array Array to scan for prefixes - * @param boolean $addNoneOption Whether to add a first entry '---' + * @param array $array Array to scan for prefixes * - * @return $prefix_array array The array conatining the unique prefixes + * @return array The array conatining the unique prefixes */ - public static function getPrefixArray($array, $addNoneOption = true) + public static function getPrefixArray($array) { $prefixes = array(); $keys = array_keys($array); diff --git a/library/Msd/Sql/Object.php b/library/Msd/Sql/Object.php index 02e3cb5..f5c296a 100644 --- a/library/Msd/Sql/Object.php +++ b/library/Msd/Sql/Object.php @@ -115,33 +115,48 @@ class Msd_Sql_Object { $pointer = $this->getPointer(); $dataSize = strlen($this->_data); - $skip = array(';', ' ', "\n", "\r"); + $skip = array(' ', "\n", "\r", "\t"); + if ($this->_state !== 'Comment') { + $skip[] = "\n"; + } if (in_array($this->_data[$pointer], $skip)) { while ($pointer < $dataSize && in_array($this->_data[$pointer], $skip)) { $pointer++; } } $this->setPointer($pointer); - if ($pointer == $this->getLength()) { + if ($pointer >= $this->getLength()) { $pointer = false; } return $pointer; } + /** + * Move pointer forward by $positions positions. + * + * @param integer $positions Move pointer forward by $positions + * + * @return void + */ + public function movePointerForward($positions) + { + $this->setPointer($this->getPointer() + $positions); + } /** - * Get some characters of data. + * Get data from actual pointer to given position. * - * @param int $nrOfCharacters Number of characters to get + * @param int $endPosition End position of pointer + * @param bool $movePointer Move pointer behind fetched data * * @return string Sql data from the pointer position to end or to the nr of chars to fetch */ - public function getData($nrOfCharacters = null) + public function getData($endPosition, $movePointer = true) { - if ($nrOfCharacters > 0) { - return substr($this->_data, $this->_pointer, $nrOfCharacters); - } else { - return substr($this->_data, $this->_pointer); + $data = substr($this->_data, $this->_pointer, ($endPosition - $this->_pointer)); + if ($movePointer === true) { + $this->setPointer($endPosition +1); } + return $data; } /** @@ -185,8 +200,8 @@ class Msd_Sql_Object * * Begins to search at the actual postion of the pointer. * - * @param string $match The string to find - * @param bool $includeMatch Whether to add length of $match to position + * @param string $match The string to find + * @param bool $includeMatch Whether to add length of $match to position * * @return int */ @@ -195,12 +210,20 @@ class Msd_Sql_Object $pointer = $this->getPointer(); $offset = $pointer; $notFound = true; - $nextHit = 0; - $length = $this->getLength() - 1; + $nextHit = false; + $length = $this->getLength() - 1; // zero-based while ($notFound && $offset < $length) { $nextHit = strpos($this->_data, $match, $offset); + //echo "
getPosition: Search for '".$match."' P: ".$offset."-> Hit at :".$nextHit; if ($nextHit === false) { - $lang = Msd_Language::getInstance()->getTranslator(); + // check special case for comments + if ($this->getState() == 'Comment' && strpos($this->_data, "\n", $pointer) === false) { + // there is no next line - return statement "as is" + $this->setPointer($this->getLength()); + return $this->getLength(); + } + // we haven't found the correct end of the query - inform user + $lang = Msd_Language::getInstance()->getTranslator(); $msg = sprintf( $lang->_('L_SQL_INCOMPLETE_STATEMENT_DETECTED'), $this->getState(), @@ -211,25 +234,51 @@ class Msd_Sql_Object $this->setPointer($this->getLength()); return false; } - // now check if we found an escaped occurance - $string = substr($this->_data, $pointer, $nextHit); - $string = str_replace('\\\\', '', trim($string)); - $quotes = substr_count($string, '\''); - $escapedQuotes = substr_count($string, '\\\''); - if (($quotes - $escapedQuotes) % 2 == 0) { + + $data = $this->getData($nextHit, false); + if (!$this->isEscaped($data)) { // hit was not escaped - we found the match $notFound = false; if ($includeMatch) { - $nextHit += strlen($match); + $nextHit += strlen($match)-1; } } else { - // keep on looking, this was escaped - $offset = $pointer + $nextHit; + // keep on looking, this one was escaped + $offset = $nextHit+1; } } return $nextHit; } + /** + * Get data upto the next new line + * + * @return string + */ + public function getDataUntilNewLine() + { + + } + + /** + * Check if hit is escaped. + * + * @param string $string String to analyse + * + * @return bool + */ + private function isEscaped($string) + { + $string = str_replace('\\\\', '', $string); + $quotes = substr_count($string, '\''); + $escapedQuotes = substr_count($string, '\\\''); + if (($quotes - $escapedQuotes) % 2 == 0) { + return false; + } else { + return true; + } + } + /** * Set an error message * diff --git a/library/Msd/Sql/Parser.php b/library/Msd/Sql/Parser.php index b8cac12..37ec994 100644 --- a/library/Msd/Sql/Parser.php +++ b/library/Msd/Sql/Parser.php @@ -82,30 +82,31 @@ class Msd_Sql_Parser implements Iterator { $statementCounter = 0; while ($this->_sql->hasMoreToProcess() && $this->_sql->movePointerToNextCommand()!==false) { - $startPosition = $this->_sql->getPointer(); - // get first "word" of query to extract the kind we have to process - $endOfFirstWord = $this->_sql->getPosition(' ', false); - // get substring from actual position to found position - $sqlQuery = $this->_sql->getData($endOfFirstWord - $startPosition); - $statement = strtolower($sqlQuery); // check for comments or conditional comments - $commentCheck = substr($sqlQuery, 0, 2); - if (isset($this->_sqlComments[$commentCheck]) || substr($statement, 0, 3) == '/*!') { + $commentCheck = $this->_sql->getData($this->_sql->getPointer() + 3, false); + if (substr($commentCheck,0 , 2) == '--' || substr($commentCheck, 0, 2) == '/*') { $statement = 'Comment'; + } else { + //$this->_sql->movePointerToNextCommand(); + // get first "word" of query to extract the kind we have to process + $endOfFirstWord = $this->_sql->getPosition(' ', false); + $sqlQuery = $this->_sql->getData($endOfFirstWord, false); + $statement = strtolower($sqlQuery); } try { $foundStatement = $this->_parseStatement($this->_sql, ucfirst($statement)); } catch (Msd_Sql_Parser_Exception $e) { // stop parsing by setting pointer to the end - $this->_sql->setPointer($this->_sql->getLength()-1); - echo "
Error: ".$e->getMessage(); + $this->_sql->setPointer($this->_sql->getLength()); } if ($this->_debug) { $this->_debugOutput .= '
Extracted statement: '.$foundStatement; } - $this->_parsedStatements[] = $foundStatement; - $statementCounter++; + if ($foundStatement > '') { + $this->_parsedStatements[] = $foundStatement; + $statementCounter++; + } // increment query type counter if (!isset($this->_parsingSummary[$statement])) { $this->_parsingSummary[$statement] = 0; diff --git a/library/Msd/Sql/Parser/Statement/Alter.php b/library/Msd/Sql/Parser/Statement/Alter.php index 352386b..6b98c00 100644 --- a/library/Msd/Sql/Parser/Statement/Alter.php +++ b/library/Msd/Sql/Parser/Statement/Alter.php @@ -30,7 +30,6 @@ class Msd_Sql_Parser_Statement_Alter implements Msd_Sql_Parser_Interface $sql->setState('Alter'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Comment.php b/library/Msd/Sql/Parser/Statement/Comment.php index 9036db6..d492cc0 100644 --- a/library/Msd/Sql/Parser/Statement/Comment.php +++ b/library/Msd/Sql/Parser/Statement/Comment.php @@ -21,18 +21,20 @@ class Msd_Sql_Parser_Statement_Comment implements Msd_Sql_Parser_Interface /** * Parse the statement. * - * @param Msd_Sql_Object $statement MySQL comment. + * @param Msd_Sql_Object $sql MySQL comment. * - * @return void + * @return string */ public function parse(Msd_Sql_Object $sql) { $sql->setState('Comment'); - $firstChars = $sql->getData(3); + $firstChars = $sql->getData($sql->getPointer() + 3, false); + $includeMatch = true; $returnStatement = false; if (substr($firstChars, 0, 2) == '--' || substr($firstChars, 0, 1) == '#') { // one line comment -> match new line $match = "\n"; + $includeMatch = false; } else { if ($firstChars == '/*!') { // conditionial statement @@ -43,13 +45,12 @@ class Msd_Sql_Parser_Statement_Comment implements Msd_Sql_Parser_Interface $match = '*/'; } } - $endOfStatement = $sql->getPosition($match); + $endOfStatement = $sql->getPosition($match, $includeMatch); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement); if ($returnStatement === true) { return $statement; } else { - return false; + return ''; } } } diff --git a/library/Msd/Sql/Parser/Statement/Create.php b/library/Msd/Sql/Parser/Statement/Create.php index e47ac9b..caaa11d 100644 --- a/library/Msd/Sql/Parser/Statement/Create.php +++ b/library/Msd/Sql/Parser/Statement/Create.php @@ -30,7 +30,6 @@ class Msd_Sql_Parser_Statement_Create implements Msd_Sql_Parser_Interface $sql->setState('Create'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Drop.php b/library/Msd/Sql/Parser/Statement/Drop.php index 9950541..3a2fd2f 100644 --- a/library/Msd/Sql/Parser/Statement/Drop.php +++ b/library/Msd/Sql/Parser/Statement/Drop.php @@ -30,7 +30,6 @@ class Msd_Sql_Parser_Statement_Drop implements Msd_Sql_Parser_Interface $sql->setState('Drop'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Insert.php b/library/Msd/Sql/Parser/Statement/Insert.php index 7de6ff5..243b15c 100644 --- a/library/Msd/Sql/Parser/Statement/Insert.php +++ b/library/Msd/Sql/Parser/Statement/Insert.php @@ -30,7 +30,6 @@ class Msd_Sql_Parser_Statement_Insert implements Msd_Sql_Parser_Interface $sql->setState('Insert'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Lock.php b/library/Msd/Sql/Parser/Statement/Lock.php index 159dfec..839b197 100644 --- a/library/Msd/Sql/Parser/Statement/Lock.php +++ b/library/Msd/Sql/Parser/Statement/Lock.php @@ -30,7 +30,6 @@ class Msd_Sql_Parser_Statement_Lock implements Msd_Sql_Parser_Interface $sql->setState('Lock'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Select.php b/library/Msd/Sql/Parser/Statement/Select.php index f3af527..97e08b8 100644 --- a/library/Msd/Sql/Parser/Statement/Select.php +++ b/library/Msd/Sql/Parser/Statement/Select.php @@ -30,7 +30,6 @@ class Msd_Sql_Parser_Statement_Select implements Msd_Sql_Parser_Interface $sql->setState('Select'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Unlock.php b/library/Msd/Sql/Parser/Statement/Unlock.php index ad10539..3a6e515 100644 --- a/library/Msd/Sql/Parser/Statement/Unlock.php +++ b/library/Msd/Sql/Parser/Statement/Unlock.php @@ -30,7 +30,6 @@ class Msd_Sql_Parser_Statement_Unlock implements Msd_Sql_Parser_Interface $sql->setState('Unlock'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement); return $statement; } }