From 2a46539fe56fea0f55980a1094d47050510c5b13 Mon Sep 17 00:00:00 2001 From: DSB Date: Mon, 20 Jun 2011 09:13:45 +0000 Subject: [PATCH] SQl-Parser: - optionally set pointer behind matches - added detection for incomplete statements SQl-Browser / SQL-Box: - output error message if query is incomplete --- application/controllers/SqlController.php | 6 +- library/Msd/Sql/Object.php | 72 +++++++++++++++++++- library/Msd/Sql/Parser.php | 6 +- library/Msd/Sql/Parser/Statement/Alter.php | 2 +- library/Msd/Sql/Parser/Statement/Comment.php | 27 +++++++- library/Msd/Sql/Parser/Statement/Create.php | 2 +- library/Msd/Sql/Parser/Statement/Drop.php | 2 +- library/Msd/Sql/Parser/Statement/Insert.php | 2 +- library/Msd/Sql/Parser/Statement/Lock.php | 2 +- library/Msd/Sql/Parser/Statement/Unlock.php | 2 +- 10 files changed, 108 insertions(+), 15 deletions(-) diff --git a/application/controllers/SqlController.php b/application/controllers/SqlController.php index 52d18ef..8a9a660 100644 --- a/application/controllers/SqlController.php +++ b/application/controllers/SqlController.php @@ -391,11 +391,15 @@ class SqlController extends Zend_Controller_Action $sqlObject = new Msd_Sql_Object($query); $parser = new Msd_Sql_Parser($sqlObject, true); $parser->parse(); + if ($sqlObject->hasErrors()) { + $this->view->errorMessage = implode('
', $sqlObject->getErrors()); + } //echo $parser->getDebugOutput(); $statements = $parser->getParsedStatements(); foreach ($statements as $statement) { + echo "
- ".$statement; try { - $res = $this->_db->query($statement, Msd_Db::ARRAY_ASSOC); + $res = array(); //$this->_db->query($statement, Msd_Db::ARRAY_ASSOC); $this->view->resultset = $res; } catch (Exception $e) { $this->view->errorMessage = $e->getMessage(); diff --git a/library/Msd/Sql/Object.php b/library/Msd/Sql/Object.php index b50919e..02e3cb5 100644 --- a/library/Msd/Sql/Object.php +++ b/library/Msd/Sql/Object.php @@ -40,6 +40,13 @@ class Msd_Sql_Object */ private $_state = ''; + /** + * Holds parsing errors. + * + * @var string + */ + private $_errors = array(); + /** * Constructor * @@ -178,11 +185,12 @@ class Msd_Sql_Object * * Begins to search at the actual postion of the pointer. * - * @param string $match + * @param string $match The string to find + * @param bool $includeMatch Whether to add length of $match to position * * @return int */ - public function getPosition($match = ';') + public function getPosition($match = ';', $includeMatch = true) { $pointer = $this->getPointer(); $offset = $pointer; @@ -192,7 +200,16 @@ class Msd_Sql_Object while ($notFound && $offset < $length) { $nextHit = strpos($this->_data, $match, $offset); if ($nextHit === false) { - return $this->getLength() - $pointer; + $lang = Msd_Language::getInstance()->getTranslator(); + $msg = sprintf( + $lang->_('L_SQL_INCOMPLETE_STATEMENT_DETECTED'), + $this->getState(), + $match, + $this->getData(200) + ); + $this->setError($msg); + $this->setPointer($this->getLength()); + return false; } // now check if we found an escaped occurance $string = substr($this->_data, $pointer, $nextHit); @@ -202,6 +219,9 @@ class Msd_Sql_Object if (($quotes - $escapedQuotes) % 2 == 0) { // hit was not escaped - we found the match $notFound = false; + if ($includeMatch) { + $nextHit += strlen($match); + } } else { // keep on looking, this was escaped $offset = $pointer + $nextHit; @@ -209,4 +229,50 @@ class Msd_Sql_Object } return $nextHit; } + + /** + * Set an error message + * + * @param string $msg The error message + * + * @return void + */ + public function setError($msg) + { + $this->_errors[] = $msg; + } + + /** + * Get error messages + * + * @return array + */ + public function getErrors() + { + return $this->_errors; + } + + /** + * Check if errors occured. + * + * @return bool + */ + public function hasErrors() + { + $ret = false; + if (sizeof($this->_errors) > 0) { + $ret = true; + } + return $ret; + } + + /** + * Get actual parsing state + * + * @return array + */ + public function getState() + { + return $this->_state; + } } diff --git a/library/Msd/Sql/Parser.php b/library/Msd/Sql/Parser.php index a1f0679..b8cac12 100644 --- a/library/Msd/Sql/Parser.php +++ b/library/Msd/Sql/Parser.php @@ -84,7 +84,7 @@ class Msd_Sql_Parser implements Iterator 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(' '); + $endOfFirstWord = $this->_sql->getPosition(' ', false); // get substring from actual position to found position $sqlQuery = $this->_sql->getData($endOfFirstWord - $startPosition); $statement = strtolower($sqlQuery); @@ -99,7 +99,7 @@ class Msd_Sql_Parser implements Iterator } 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(); + echo "
Error: ".$e->getMessage(); } if ($this->_debug) { $this->_debugOutput .= '
Extracted statement: '.$foundStatement; @@ -128,7 +128,7 @@ class Msd_Sql_Parser implements Iterator { $statementPath = '/Msd/Sql/Parser/Statement/' . $statement; if (!file_exists(LIBRARY_PATH . $statementPath . '.php')) { - throw new Msd_Sql_Parser_Exception("Can't find statement class for statement: " . $statement); + throw new Msd_Sql_Parser_Exception("Can't find statement class for statement: '" . $statement ."'"); } $statementClass = 'Msd_Sql_Parser_Statement_' . $statement; $parserObject = new $statementClass(); diff --git a/library/Msd/Sql/Parser/Statement/Alter.php b/library/Msd/Sql/Parser/Statement/Alter.php index 4374212..352386b 100644 --- a/library/Msd/Sql/Parser/Statement/Alter.php +++ b/library/Msd/Sql/Parser/Statement/Alter.php @@ -30,7 +30,7 @@ class Msd_Sql_Parser_Statement_Alter implements Msd_Sql_Parser_Interface $sql->setState('Alter'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement+1); + $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Comment.php b/library/Msd/Sql/Parser/Statement/Comment.php index 1485253..9036db6 100644 --- a/library/Msd/Sql/Parser/Statement/Comment.php +++ b/library/Msd/Sql/Parser/Statement/Comment.php @@ -25,8 +25,31 @@ class Msd_Sql_Parser_Statement_Comment implements Msd_Sql_Parser_Interface * * @return void */ - public function parse(Msd_Sql_Object$statement) + public function parse(Msd_Sql_Object $sql) { - return $statement; + $sql->setState('Comment'); + $firstChars = $sql->getData(3); + $returnStatement = false; + if (substr($firstChars, 0, 2) == '--' || substr($firstChars, 0, 1) == '#') { + // one line comment -> match new line + $match = "\n"; + } else { + if ($firstChars == '/*!') { + // conditionial statement + $match = '*/;'; + $returnStatement = true; + } else { + // multi line comment + $match = '*/'; + } + } + $endOfStatement = $sql->getPosition($match); + $statement = $sql->getData($endOfStatement); + $sql->setPointer($endOfStatement); + if ($returnStatement === true) { + return $statement; + } else { + return false; + } } } diff --git a/library/Msd/Sql/Parser/Statement/Create.php b/library/Msd/Sql/Parser/Statement/Create.php index 72d49f8..e47ac9b 100644 --- a/library/Msd/Sql/Parser/Statement/Create.php +++ b/library/Msd/Sql/Parser/Statement/Create.php @@ -30,7 +30,7 @@ class Msd_Sql_Parser_Statement_Create implements Msd_Sql_Parser_Interface $sql->setState('Create'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement+1); + $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Drop.php b/library/Msd/Sql/Parser/Statement/Drop.php index 8302f7f..9950541 100644 --- a/library/Msd/Sql/Parser/Statement/Drop.php +++ b/library/Msd/Sql/Parser/Statement/Drop.php @@ -30,7 +30,7 @@ class Msd_Sql_Parser_Statement_Drop implements Msd_Sql_Parser_Interface $sql->setState('Drop'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement+1); + $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Insert.php b/library/Msd/Sql/Parser/Statement/Insert.php index 09d5aec..7de6ff5 100644 --- a/library/Msd/Sql/Parser/Statement/Insert.php +++ b/library/Msd/Sql/Parser/Statement/Insert.php @@ -30,7 +30,7 @@ class Msd_Sql_Parser_Statement_Insert implements Msd_Sql_Parser_Interface $sql->setState('Insert'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement+1); + $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Lock.php b/library/Msd/Sql/Parser/Statement/Lock.php index f206965..159dfec 100644 --- a/library/Msd/Sql/Parser/Statement/Lock.php +++ b/library/Msd/Sql/Parser/Statement/Lock.php @@ -30,7 +30,7 @@ class Msd_Sql_Parser_Statement_Lock implements Msd_Sql_Parser_Interface $sql->setState('Lock'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement+1); + $sql->setPointer($endOfStatement); return $statement; } } diff --git a/library/Msd/Sql/Parser/Statement/Unlock.php b/library/Msd/Sql/Parser/Statement/Unlock.php index 3c28afb..ad10539 100644 --- a/library/Msd/Sql/Parser/Statement/Unlock.php +++ b/library/Msd/Sql/Parser/Statement/Unlock.php @@ -30,7 +30,7 @@ class Msd_Sql_Parser_Statement_Unlock implements Msd_Sql_Parser_Interface $sql->setState('Unlock'); $endOfStatement = $sql->getPosition(';'); $statement = $sql->getData($endOfStatement); - $sql->setPointer($endOfStatement+1); + $sql->setPointer($endOfStatement); return $statement; } }