SQL-Parser:
- implemented a new sql-object that can be handed over to the statement parsing classes (Implemented only for select for now) QA Added library path constant to public/index.php
Dieser Commit ist enthalten in:
Ursprung
3bedcd0421
Commit
eef38cec0c
12 geänderte Dateien mit 261 neuen und 106 gelöschten Zeilen
|
@ -388,9 +388,10 @@ class SqlController extends Zend_Controller_Action
|
|||
$query = trim($query);
|
||||
if ($query > '') {
|
||||
$this->_db->selectDb($config->get('dynamic.dbActual'));
|
||||
$parser = new Msd_Sql_Parser($query, true);
|
||||
$sqlObject = new Msd_Sql_Object($query);
|
||||
$parser = new Msd_Sql_Parser($sqlObject, true);
|
||||
$parser->parse();
|
||||
print_r($parser->getDebugOutput());
|
||||
//echo $parser->getDebugOutput();
|
||||
$statements = $parser->getParsedStatements();
|
||||
foreach ($statements as $statement) {
|
||||
try {
|
||||
|
|
208
library/Msd/Sql/Object.php
Normale Datei
208
library/Msd/Sql/Object.php
Normale Datei
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of MySQLDumper released under the GNU/GPL 2 license
|
||||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to represent sql data to be parsed.
|
||||
* Object is intended to be handed over to the parser classes so that they can work on it.
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Parser
|
||||
*/
|
||||
class Msd_Sql_Object
|
||||
{
|
||||
/**
|
||||
* Holds string data to be parsed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_data = '';
|
||||
|
||||
/**
|
||||
* Holdes a pointer to the actual examined part as offset.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_pointer = 0;
|
||||
|
||||
/**
|
||||
* Holds the parsing state.
|
||||
* This is set by the data examining methods of the parser and reflects the parser mode (select, insert, ...)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_state = '';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param null $sqlData SQl data to be parsed
|
||||
*/
|
||||
public function __construct($sqlData = null)
|
||||
{
|
||||
$this->_data = $sqlData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data of object
|
||||
*
|
||||
* @param string $sqlData The queries
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setData($sqlData = '')
|
||||
{
|
||||
$this->_data = $sqlData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append data to already given data.
|
||||
*
|
||||
* @param string $sqlData The sql-string to be appended
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function appendData($sqlData)
|
||||
{
|
||||
$this->_data .= $sqlData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actual position of the pointer.
|
||||
*
|
||||
* @return int Pointer position
|
||||
*/
|
||||
public function getPointer()
|
||||
{
|
||||
return $this->_pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the actual position of the pointer.
|
||||
*
|
||||
* @param int $position Position of pointer
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPointer($position)
|
||||
{
|
||||
$this->_pointer = $position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move pointer to the beginning of the next command.
|
||||
*
|
||||
* Skip all spaces and line-breaks until a character is found that might be the beginning
|
||||
* of a new sql command.
|
||||
*
|
||||
* @return int New pointer position
|
||||
*/
|
||||
public function movePointerToNextCommand()
|
||||
{
|
||||
$pointer = $this->getPointer();
|
||||
$dataSize = strlen($this->_data);
|
||||
$skip = array(';', ' ', "\n", "\r");
|
||||
while ($pointer < $dataSize && in_array($this->_data[$pointer], $skip)) {
|
||||
$pointer++;
|
||||
}
|
||||
$this->setPointer($pointer);
|
||||
return $pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get some characters of data.
|
||||
*
|
||||
* @param int $nrOfCharacters Number of characters to get
|
||||
*
|
||||
* @return string Sql data from the pointer position to end or to the nr of chars to fetch
|
||||
*/
|
||||
public function getData($nrOfCharacters = null)
|
||||
{
|
||||
if ($nrOfCharacters > 0) {
|
||||
return substr($this->_data, $this->_pointer, $nrOfCharacters);
|
||||
} else {
|
||||
return substr($this->_data, $this->_pointer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get length of data string.
|
||||
*
|
||||
* @return int Length of data string
|
||||
*/
|
||||
public function getLength()
|
||||
{
|
||||
return strlen($this->_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if pointer has reached the end of the data string.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasMoreToProcess()
|
||||
{
|
||||
if ($this->_pointer < $this->getLength()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parser state.
|
||||
*
|
||||
* @param string $state The parsing state we are actually in.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setState($state)
|
||||
{
|
||||
$this->_state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next unescaped occurance of $match.
|
||||
*
|
||||
* Begins to search at the actual postion of the pointer.
|
||||
*
|
||||
* @param string $match
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPosition($match = ';')
|
||||
{
|
||||
$pointer = $this->getPointer();
|
||||
$offset = $pointer;
|
||||
$notFound = true;
|
||||
$length = $this->getLength()-1;
|
||||
while ($notFound && $offset < $length) {
|
||||
//echo "<br>Checking: ". substr($this->_data, $offset);
|
||||
$nextHit = strpos($this->_data, $match, $offset);
|
||||
//echo "<br>Next hit is :".intval($nextHit);
|
||||
if ($nextHit === false) {
|
||||
$nextHit = $this->getLength() - $pointer;
|
||||
}
|
||||
// now check if we found an escaped occurance
|
||||
$string = substr($this->_data, $pointer, $nextHit);
|
||||
$string=str_replace('\\\\','',trim($string));
|
||||
$quotes=substr_count($string,'\'');
|
||||
$escaped_quotes=substr_count($string,'\\\'');
|
||||
if (($quotes-$escaped_quotes) % 2 == 0) {
|
||||
// hit was not escaped - we found the match
|
||||
$notFound = false;
|
||||
} else {
|
||||
// keep on looking, this was escaped
|
||||
$offset = $pointer + $nextHit +1;
|
||||
}
|
||||
}
|
||||
return $nextHit;
|
||||
}
|
||||
}
|
|
@ -4,12 +4,11 @@
|
|||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
||||
require_once "Msd/Sql/Parser/Interface.php";
|
||||
/**
|
||||
* Class to parse MySQL queries.
|
||||
* This enables you to analyze and modify MySQL queries, which the user has entered.
|
||||
|
@ -69,14 +68,12 @@ class Msd_Sql_Parser implements Iterator
|
|||
* Class constructor.
|
||||
* Creates a new instance of the MySQL parser and optionally assign the raw MySQL query.
|
||||
*
|
||||
* @param string $sqlQuery Raw MySQL query to parse
|
||||
* @param Msd_Sql_Object $sqlObject SQL-Object holding the data to be parsed
|
||||
* @param bool $debug If turned on, detection of queries is logged
|
||||
*/
|
||||
public function __construct($sqlQuery = null, $debug = false)
|
||||
public function __construct(Msd_Sql_Object $sqlObject, $debug = false)
|
||||
{
|
||||
if ($sqlQuery !== null) {
|
||||
$this->_rawQuery = $sqlQuery;
|
||||
}
|
||||
$this->_sql = $sqlObject;
|
||||
$this->_debug = $debug;
|
||||
}
|
||||
|
||||
|
@ -86,61 +83,32 @@ class Msd_Sql_Parser implements Iterator
|
|||
*
|
||||
* @throws Msd_Sql_Parser_Exception
|
||||
*
|
||||
* @param string $sqlQuery Raw MySQL query to parse
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse($sqlQuery = null)
|
||||
public function parse()
|
||||
{
|
||||
if ($sqlQuery === null) {
|
||||
if ($this->_rawQuery === null) {
|
||||
throw new Msd_Sql_Parser_Exception('You must specify a MySQL query for parsing!');
|
||||
}
|
||||
$sqlQuery = $this->_rawQuery;
|
||||
}
|
||||
|
||||
$sqlQuery = trim($sqlQuery);
|
||||
|
||||
// get first characters to extract the kind of query we have to process
|
||||
$statementCounter = 0;
|
||||
$startPos = 0;
|
||||
$queryLength = strlen($sqlQuery);
|
||||
while ($startPos < $queryLength) {
|
||||
$statementCounter++;
|
||||
// move pointer to the next character we can interprete
|
||||
while ($startPos < $queryLength && in_array($sqlQuery[$startPos], array(' ', "\n", "\r"))) {
|
||||
$startPos++;
|
||||
}
|
||||
while ($this->_sql->hasMoreToProcess()) {
|
||||
$this->_sql->movePointerToNextCommand();
|
||||
$endOfCommand = $this->_sql->getPosition(' ');
|
||||
$sqlQuery = $this->_sql->getData($endOfCommand);
|
||||
//echo "<br>Query beginn: ".$sqlQuery;
|
||||
|
||||
$firstSpace = strpos($sqlQuery, ' ', $startPos);
|
||||
$statement = trim(strtolower(substr($sqlQuery, $startPos, $firstSpace - $startPos)));
|
||||
$lengthCheck = strlen($statement);
|
||||
if ($lengthCheck == 0) {
|
||||
break;
|
||||
}
|
||||
if ($lengthCheck == 1 || $statement{1} == ';' || $statement{1} == "\n") {
|
||||
$startPos = $startPos + 1;
|
||||
continue;
|
||||
}
|
||||
$parts = explode(' ', $sqlQuery);
|
||||
$statement = strtolower($parts[0]);
|
||||
// check for comments or conditional comments
|
||||
$commentCheck = substr($statement, 0, 2);
|
||||
$commentCheck = substr($sqlQuery, 0, 2);
|
||||
if (isset($this->_sqlComments[$commentCheck]) || substr($statement, 0, 3) == '/*!') {
|
||||
$commentEnd = $this->_sqlComments[$commentCheck];
|
||||
$endPos = strpos($sqlQuery, $commentEnd, $startPos) + strlen($commentEnd);
|
||||
$comment = substr($sqlQuery, $startPos, $endPos - $startPos);
|
||||
$this->_parseStatement($comment, 'Msd_Sql_Parser_Statement_Comment');
|
||||
$startPos = $endPos+1;
|
||||
continue;
|
||||
$statement = 'Comment';
|
||||
}
|
||||
|
||||
$parserClass = 'Msd_Sql_Parser_Statement_' . ucwords($statement);
|
||||
$endPos = $this->_getStatementEndPos($sqlQuery, $startPos);
|
||||
$completeStatement = trim(substr($sqlQuery, $startPos, $endPos - $startPos));
|
||||
$startPos = $endPos + 1;
|
||||
$foundStatement = $this->_parseStatement($completeStatement, $parserClass);
|
||||
$foundStatement = $this->_parseStatement($this->_sql, ucwords($statement));
|
||||
if ($this->_debug) {
|
||||
$this->_debugOutput .= '<br />Extracted statement: '.$foundStatement;
|
||||
}
|
||||
$this->_parsedStatements[] = $foundStatement;
|
||||
$statementCounter++;
|
||||
// increment query type counter
|
||||
if (!isset($this->_parsingSummary[$statement])) {
|
||||
$this->_parsingSummary[$statement] = 0;
|
||||
|
@ -149,57 +117,26 @@ class Msd_Sql_Parser implements Iterator
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the end of a MySQL statement and returns its position.
|
||||
*
|
||||
* @param string $sqlQuery The complete MySQL query
|
||||
* @param int $startPos Index, where to start the search.
|
||||
*
|
||||
* @return int End position of the statement
|
||||
*/
|
||||
private function _getStatementEndPos($sqlQuery, $startPos = 0)
|
||||
{
|
||||
$nextString = strpos($sqlQuery, "'", $startPos);
|
||||
$nextSemicolon = strpos($sqlQuery, ';', $startPos);
|
||||
if ($nextString === false) {
|
||||
if ($nextSemicolon === false) {
|
||||
return strlen($sqlQuery);
|
||||
}
|
||||
|
||||
return $nextSemicolon+1;
|
||||
}
|
||||
|
||||
while ($nextString < $nextSemicolon) {
|
||||
$nextString = strpos($sqlQuery, "'", $nextString + 1);
|
||||
$nextSemicolon = strpos($sqlQuery, ';', $nextString + 1);
|
||||
$nextString = strpos($sqlQuery, "'", $nextString + 1);
|
||||
if ($nextString === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $nextSemicolon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of a statement parser class and invokes statement parsing.
|
||||
*
|
||||
* @throws Msd_Sql_Parser_Exception
|
||||
*
|
||||
* @param string $statement MySQL statement to parse
|
||||
* @param string $parserClass Parser class to use
|
||||
* @param Msd_Sql_Object $sqlObject MySQL statement to parse
|
||||
* @param string $statement Parser class to use
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _parseStatement($statement, $parserClass)
|
||||
private function _parseStatement(Msd_Sql_Object $sqlObject, $statement)
|
||||
{
|
||||
try {
|
||||
$parserObject = new $parserClass;
|
||||
} catch (Exception $e) {
|
||||
throw new Msd_Sql_Parser_Exception("Can't suitable parser for the statement!");
|
||||
$statementPath = '/Msd/Sql/Parser/Statement/' . $statement;
|
||||
if ($statement !== 'Select') die("Not implemented yet: ".$statement);
|
||||
if (!file_exists(LIBRARY_PATH . $statementPath . '.php')) {
|
||||
throw new Msd_Sql_Parser_Exception("Can't find statement class for statement: " . $statement);
|
||||
}
|
||||
|
||||
return $parserObject->parse($statement);
|
||||
$statementClass = 'Msd_Sql_Parser_Statement_' . $statement;
|
||||
$parserObject = new $statementClass;
|
||||
return $parserObject->parse($sqlObject);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
||||
require_once 'Msd/Exception.php';
|
||||
/**
|
||||
* Exception class for all SQL-Parser exceptions.
|
||||
*
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
@ -13,7 +13,7 @@
|
|||
* Interface definition for MySQL statement parsers.
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
*/
|
||||
interface Msd_Sql_Parser_Interface
|
||||
{
|
||||
|
@ -22,9 +22,9 @@ interface Msd_Sql_Parser_Interface
|
|||
*
|
||||
* @abstract
|
||||
*
|
||||
* @param string $statement MySQL statement.
|
||||
* @param Msd_Sql_Object $sqlObject MySQL statement object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse($statement);
|
||||
public function parse(Msd_Sql_Object $sqlObject);
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
@ -25,8 +25,12 @@ class Msd_Sql_Parser_Statement_Select implements Msd_Sql_Parser_Interface
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse($statement)
|
||||
public function parse(Msd_Sql_Object $sql)
|
||||
{
|
||||
$sql->setState('Select');
|
||||
$endOfStatement = $sql->getPosition(';');
|
||||
$statement = $sql->getData($endOfStatement);
|
||||
$sql->setPointer($endOfStatement+1);
|
||||
return $statement;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* http://www.mysqldumper.net
|
||||
*
|
||||
* @package MySQLDumper
|
||||
* @subpackage SQL-Browser
|
||||
* @subpackage SQL-Parser
|
||||
* @version SVN: $Rev$
|
||||
* @author $Author$
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,12 @@ defined('APPLICATION_PATH') || define(
|
|||
)
|
||||
);
|
||||
|
||||
defined('LIBRARY_PATH') || define(
|
||||
'LIBRARY_PATH', realpath(
|
||||
dirname(__FILE__) . DS . '..' . DS . 'library'
|
||||
)
|
||||
);
|
||||
|
||||
// Define application environment
|
||||
if (!defined('APPLICATION_ENV')) {
|
||||
$appEnvironment = getenv('APPLICATION_ENV');
|
||||
|
|
Laden …
In neuem Issue referenzieren