summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes8
-rw-r--r--CHANGELOG.md10
-rw-r--r--README.md7
-rw-r--r--composer.json5
-rw-r--r--phpunit.xml2
-rw-r--r--src/Components/Expression.php1
-rw-r--r--src/Lexer.php154
-rw-r--r--src/Utils/Formatter.php66
-rw-r--r--tests/Parser/SelectStatementTest.php2
-rw-r--r--tests/TestCase.php (renamed from tests/bootstrap.php)3
-rw-r--r--tests/Utils/CLITest.php8
-rw-r--r--tests/Utils/FormatterTest.php60
-rw-r--r--tests/data/parser/parseSelect11.in1
-rw-r--r--tests/data/parser/parseSelect11.out4
-rw-r--r--tests/data/parser/parseSelectErr2.in1
-rw-r--r--tests/data/parser/parseSelectErr2.out4
-rw-r--r--tools/ContextGenerator.php2
17 files changed, 210 insertions, 128 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..63c9828
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,8 @@
+/tests export-ignore
+/tools export-ignore
+.gitattributes export-ignore
+.gitignore export-ignore
+.travis.yml export-ignore
+codeconv.yml export-ignore
+phpunit.xml export-ignore
+.php_cs export-ignore
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fe8df4d..a545678 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,13 +2,21 @@
## [Unreleased]
+* Coding style fixes.
+* Fixed indentation in HTML formatting.
+* Fixed parsing of unterminated variables.
+
+## [3.4.16] - 2017-01-06
+
+* Coding style fixes.
+* Properly handle operators AND, NOT, OR, XOR, DIV, MOD
+
## [3.4.15] - 2017-01-02
* Fix return value of Formatter.toString() when type is text
* Fix parsing of FIELDS and LINES options in SELECT..INTO
* PHP 7.2 compatibility.
* Better parameter passing to query formatter.
-* Coding style fixes.
## [3.4.14] - 2016-11-30
diff --git a/README.md b/README.md
index 88d81e5..6aebabf 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,13 @@ $parser->statements[0]->from[0] = $table2;
$statement = $parser->statements[0];
$query2 = $statement->build();
var_dump($query2); // outputs string(19) "SELECT * FROM `b` "
+
+// Change SQL mode
+SqlParser\Context::setMode('ANSI_QUOTES');
+
+// build the query again using different quotes
+$query2 = $statement->build();
+var_dump($query2); // outputs string(19) "SELECT * FROM "b" "
```
## More information
diff --git a/composer.json b/composer.json
index 4eb69e9..0b59e56 100644
--- a/composer.json
+++ b/composer.json
@@ -32,5 +32,10 @@
"psr-4": {
"SqlParser\\": "src"
}
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "SqlParser\\Tests\\": "tests"
+ }
}
}
diff --git a/phpunit.xml b/phpunit.xml
index f307622..ac69326 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
- bootstrap="tests/bootstrap.php"
+ bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
diff --git a/src/Components/Expression.php b/src/Components/Expression.php
index 9c74b20..04466b0 100644
--- a/src/Components/Expression.php
+++ b/src/Components/Expression.php
@@ -30,6 +30,7 @@ class Expression extends Component
*/
private static $ALLOWED_KEYWORDS = array(
'AS' => 1, 'DUAL' => 1, 'NULL' => 1, 'REGEXP' => 1, 'CASE' => 1,
+ 'DIV' => 1, 'AND' => 1, 'OR' => 1, 'XOR' => 1, 'NOT' => 1, 'MOD' => 1,
);
/**
diff --git a/src/Lexer.php b/src/Lexer.php
index 3ab5f5a..08dd09a 100644
--- a/src/Lexer.php
+++ b/src/Lexer.php
@@ -161,18 +161,16 @@ class Lexer extends Core
{
// `strlen` is used instead of `mb_strlen` because the lexer needs to
// parse each byte of the input.
- $len = ($str instanceof UtfString) ? $str->length() : strlen($str);
+ $len = $str instanceof UtfString ? $str->length() : strlen($str);
// For multi-byte strings, a new instance of `UtfString` is
// initialized (only if `UtfString` usage is forced.
- if (!($str instanceof UtfString)) {
- if ((USE_UTF_STRINGS) && ($len !== mb_strlen($str, 'UTF-8'))) {
- $str = new UtfString($str);
- }
+ if (!$str instanceof UtfString && USE_UTF_STRINGS && $len !== mb_strlen($str, 'UTF-8')) {
+ $str = new UtfString($str);
}
$this->str = $str;
- $this->len = ($str instanceof UtfString) ? $str->length() : $len;
+ $this->len = $str instanceof UtfString ? $str->length() : $len;
$this->strict = $strict;
@@ -227,7 +225,7 @@ class Lexer extends Core
$token = null;
foreach (static::$PARSER_METHODS as $method) {
- if (($token = $this->$method())) {
+ if ($token = $this->$method()) {
break;
}
}
@@ -240,12 +238,16 @@ class Lexer extends Core
$this->str[$this->last],
$this->last
);
- } elseif (($lastToken !== null)
- && ($token->type === Token::TYPE_SYMBOL)
- && ($token->flags & Token::FLAG_SYMBOL_VARIABLE)
- && (($lastToken->type === Token::TYPE_STRING)
- || (($lastToken->type === Token::TYPE_SYMBOL)
- && ($lastToken->flags & Token::FLAG_SYMBOL_BACKTICK)))
+ } elseif ($lastToken !== null
+ && $token->type === Token::TYPE_SYMBOL
+ && $token->flags & Token::FLAG_SYMBOL_VARIABLE
+ && (
+ $lastToken->type === Token::TYPE_STRING
+ || (
+ $lastToken->type === Token::TYPE_SYMBOL
+ && $lastToken->flags & Token::FLAG_SYMBOL_BACKTICK
+ )
+ )
) {
// Handles ```... FROM 'user'@'%' ...```.
$lastToken->token .= $token->token;
@@ -253,10 +255,10 @@ class Lexer extends Core
$lastToken->flags = Token::FLAG_SYMBOL_USER;
$lastToken->value .= '@' . $token->value;
continue;
- } elseif (($lastToken !== null)
- && ($token->type === Token::TYPE_KEYWORD)
- && ($lastToken->type === Token::TYPE_OPERATOR)
- && ($lastToken->value === '.')
+ } elseif ($lastToken !== null
+ && $token->type === Token::TYPE_KEYWORD
+ && $lastToken->type === Token::TYPE_OPERATOR
+ && $lastToken->value === '.'
) {
// Handles ```... tbl.FROM ...```. In this case, FROM is not
// a reserved word.
@@ -270,7 +272,7 @@ class Lexer extends Core
$list->tokens[$list->count++] = $token;
// Handling delimiters.
- if (($token->type === Token::TYPE_NONE) && ($token->value === 'DELIMITER')) {
+ if ($token->type === Token::TYPE_NONE && $token->value === 'DELIMITER') {
if ($this->last + 1 >= $this->len) {
$this->error(
'Expected whitespace(s) before delimiter.',
@@ -301,7 +303,7 @@ class Lexer extends Core
// Parsing the delimiter.
$this->delimiter = null;
- while ((++$this->last < $this->len) && (!Context::isWhitespace($this->str[$this->last]))) {
+ while (++$this->last < $this->len && !Context::isWhitespace($this->str[$this->last])) {
$this->delimiter .= $this->str[$this->last];
}
@@ -395,16 +397,17 @@ class Lexer extends Core
} else {
$lastSpace = false;
}
+
$token .= $this->str[$this->last];
- if (($this->last + 1 === $this->len) || (Context::isSeparator($this->str[$this->last + 1]))) {
- if (($flags = Context::isKeyword($token))) {
- $ret = new Token($token, Token::TYPE_KEYWORD, $flags);
- $iEnd = $this->last;
-
- // We don't break so we find longest keyword.
- // For example, `OR` and `ORDER` have a common prefix `OR`.
- // If we stopped at `OR`, the parsing would be invalid.
- }
+ if (($this->last + 1 === $this->len || Context::isSeparator($this->str[$this->last + 1]))
+ && $flags = Context::isKeyword($token)
+ ) {
+ $ret = new Token($token, Token::TYPE_KEYWORD, $flags);
+ $iEnd = $this->last;
+
+ // We don't break so we find longest keyword.
+ // For example, `OR` and `ORDER` have a common prefix `OR`.
+ // If we stopped at `OR`, the parsing would be invalid.
}
}
@@ -518,7 +521,7 @@ class Lexer extends Core
return null;
}
- while ((++$this->last < $this->len) && (Context::isWhitespace($this->str[$this->last]))) {
+ while (++$this->last < $this->len && Context::isWhitespace($this->str[$this->last])) {
$token .= $this->str[$this->last];
}
@@ -539,7 +542,10 @@ class Lexer extends Core
// Bash style comments. (#comment\n)
if (Context::isComment($token)) {
- while ((++$this->last < $this->len) && ($this->str[$this->last] !== "\n")) {
+ while (
+ ++$this->last < $this->len
+ && $this->str[$this->last] !== "\n"
+ ) {
$token .= $this->str[$this->last];
}
$token .= "\n"; // Adding the line ending.
@@ -559,13 +565,16 @@ class Lexer extends Core
}
// Checking if this is a MySQL-specific command.
- if (($this->last + 1 < $this->len) && ($this->str[$this->last + 1] === '!')) {
+ if ($this->last + 1 < $this->len
+ && $this->str[$this->last + 1] === '!'
+ ) {
$flags |= Token::FLAG_COMMENT_MYSQL_CMD;
$token .= $this->str[++$this->last];
- while ((++$this->last < $this->len)
- && ('0' <= $this->str[$this->last])
- && ($this->str[$this->last] <= '9')
+ while (
+ ++$this->last < $this->len
+ && '0' <= $this->str[$this->last]
+ && $this->str[$this->last] <= '9'
) {
$token .= $this->str[$this->last];
}
@@ -577,8 +586,12 @@ class Lexer extends Core
}
// Parsing the comment.
- while ((++$this->last < $this->len)
- && (($this->str[$this->last - 1] !== '*') || ($this->str[$this->last] !== '/'))
+ while (
+ ++$this->last < $this->len
+ && (
+ $this->str[$this->last - 1] !== '*'
+ || $this->str[$this->last] !== '/'
+ )
) {
$token .= $this->str[$this->last];
}
@@ -598,7 +611,10 @@ class Lexer extends Core
if (Context::isComment($token)) {
// Checking if this comment did not end already (```--\n```).
if ($this->str[$this->last] !== "\n") {
- while ((++$this->last < $this->len) && ($this->str[$this->last] !== "\n")) {
+ while (
+ ++$this->last < $this->len
+ && $this->str[$this->last] !== "\n"
+ ) {
$token .= $this->str[$this->last];
}
$token .= "\n"; // Adding the line ending.
@@ -695,14 +711,16 @@ class Lexer extends Core
if ($state === 1) {
if ($this->str[$this->last] === '-') {
$flags |= Token::FLAG_NUMBER_NEGATIVE;
- } elseif (($this->last + 1 < $this->len)
- && ($this->str[$this->last] === '0')
- && (($this->str[$this->last + 1] === 'x')
- || ($this->str[$this->last + 1] === 'X'))
+ } elseif ($this->last + 1 < $this->len
+ && $this->str[$this->last] === '0'
+ && (
+ $this->str[$this->last + 1] === 'x'
+ || $this->str[$this->last + 1] === 'X'
+ )
) {
$token .= $this->str[$this->last++];
$state = 2;
- } elseif (($this->str[$this->last] >= '0') && ($this->str[$this->last] <= '9')) {
+ } elseif ($this->str[$this->last] >= '0' && $this->str[$this->last] <= '9') {
$state = 3;
} elseif ($this->str[$this->last] === '.') {
$state = 4;
@@ -714,40 +732,43 @@ class Lexer extends Core
}
} elseif ($state === 2) {
$flags |= Token::FLAG_NUMBER_HEX;
- if (!((($this->str[$this->last] >= '0') && ($this->str[$this->last] <= '9'))
- || (($this->str[$this->last] >= 'A') && ($this->str[$this->last] <= 'F'))
- || (($this->str[$this->last] >= 'a') && ($this->str[$this->last] <= 'f')))
+ if (
+ !(
+ ($this->str[$this->last] >= '0' && $this->str[$this->last] <= '9')
+ || ($this->str[$this->last] >= 'A' && $this->str[$this->last] <= 'F')
+ || ($this->str[$this->last] >= 'a' && $this->str[$this->last] <= 'f')
+ )
) {
break;
}
} elseif ($state === 3) {
if ($this->str[$this->last] === '.') {
$state = 4;
- } elseif (($this->str[$this->last] === 'e') || ($this->str[$this->last] === 'E')) {
+ } elseif ($this->str[$this->last] === 'e' || $this->str[$this->last] === 'E') {
$state = 5;
- } elseif (($this->str[$this->last] < '0') || ($this->str[$this->last] > '9')) {
+ } elseif ($this->str[$this->last] < '0' || $this->str[$this->last] > '9') {
// Just digits and `.`, `e` and `E` are valid characters.
break;
}
} elseif ($state === 4) {
$flags |= Token::FLAG_NUMBER_FLOAT;
- if (($this->str[$this->last] === 'e') || ($this->str[$this->last] === 'E')) {
+ if ($this->str[$this->last] === 'e' || $this->str[$this->last] === 'E') {
$state = 5;
- } elseif (($this->str[$this->last] < '0') || ($this->str[$this->last] > '9')) {
+ } elseif ($this->str[$this->last] < '0' || $this->str[$this->last] > '9') {
// Just digits, `e` and `E` are valid characters.
break;
}
} elseif ($state === 5) {
$flags |= Token::FLAG_NUMBER_APPROXIMATE;
- if (($this->str[$this->last] === '+') || ($this->str[$this->last] === '-')
- || ((($this->str[$this->last] >= '0') && ($this->str[$this->last] <= '9')))
+ if ($this->str[$this->last] === '+' || $this->str[$this->last] === '-'
+ || ($this->str[$this->last] >= '0' && $this->str[$this->last] <= '9')
) {
$state = 6;
} else {
break;
}
} elseif ($state === 6) {
- if (($this->str[$this->last] < '0') || ($this->str[$this->last] > '9')) {
+ if ($this->str[$this->last] < '0' || $this->str[$this->last] > '9') {
// Just digits are valid characters.
break;
}
@@ -761,8 +782,8 @@ class Lexer extends Core
} elseif ($state === 8) {
if ($this->str[$this->last] === '\'') {
$state = 9;
- } elseif (($this->str[$this->last] !== '0')
- && ($this->str[$this->last] !== '1')
+ } elseif ($this->str[$this->last] !== '0'
+ && $this->str[$this->last] !== '1'
) {
break;
}
@@ -771,9 +792,9 @@ class Lexer extends Core
}
$token .= $this->str[$this->last];
}
- if (($state === 2) || ($state === 3)
- || (($token !== '.') && ($state === 4))
- || ($state === 6) || ($state === 9)
+ if ($state === 2 || $state === 3
+ || ($token !== '.' && $state === 4)
+ || $state === 6 || $state === 9
) {
--$this->last;
@@ -794,15 +815,17 @@ class Lexer extends Core
public function parseString($quote = '')
{
$token = $this->str[$this->last];
- if ((!($flags = Context::isString($token))) && ($token !== $quote)) {
+ if (!($flags = Context::isString($token)) && $token !== $quote) {
return null;
}
$quote = $token;
while (++$this->last < $this->len) {
- if (($this->last + 1 < $this->len)
- && ((($this->str[$this->last] === $quote) && ($this->str[$this->last + 1] === $quote))
- || (($this->str[$this->last] === '\\') && ($quote !== '`')))
+ if ($this->last + 1 < $this->len
+ && (
+ ($this->str[$this->last] === $quote && $this->str[$this->last + 1] === $quote)
+ || ($this->str[$this->last] === '\\' && $quote !== '`')
+ )
) {
$token .= $this->str[$this->last] . $this->str[++$this->last];
} else {
@@ -813,7 +836,7 @@ class Lexer extends Core
}
}
- if (($this->last >= $this->len) || ($this->str[$this->last] !== $quote)) {
+ if ($this->last >= $this->len || $this->str[$this->last] !== $quote) {
$this->error(
sprintf(
Translator::gettext('Ending quote %1$s was expected.'),
@@ -842,7 +865,7 @@ class Lexer extends Core
}
if ($flags & Token::FLAG_SYMBOL_VARIABLE) {
- if ($this->str[++$this->last] === '@') {
+ if ($this->last + 1 < $this->len && $this->str[++$this->last] === '@') {
// This is a system variable (e.g. `@@hostname`).
$token .= $this->str[$this->last++];
$flags |= Token::FLAG_SYMBOL_SYSTEM;
@@ -883,7 +906,8 @@ class Lexer extends Core
if (Context::isSeparator($token)) {
return null;
}
- while ((++$this->last < $this->len) && (!Context::isSeparator($this->str[$this->last]))) {
+
+ while (++$this->last < $this->len && !Context::isSeparator($this->str[$this->last])) {
$token .= $this->str[$this->last];
}
--$this->last;
@@ -900,7 +924,7 @@ class Lexer extends Core
{
$idx = 0;
- while (($idx < $this->delimiterLen) && ($this->last + $idx < $this->len)) {
+ while ($idx < $this->delimiterLen && $this->last + $idx < $this->len) {
if ($this->delimiter[$idx] !== $this->str[$this->last + $idx]) {
return null;
}
diff --git a/src/Utils/Formatter.php b/src/Utils/Formatter.php
index ec23ba9..22effca 100644
--- a/src/Utils/Formatter.php
+++ b/src/Utils/Formatter.php
@@ -78,6 +78,10 @@ class Formatter
$options['line_ending'] = $options['type'] === 'html' ? '<br/>' : "\n";
}
+ if (is_null($options['indentation'])) {
+ $options['indentation'] = $options['type'] === 'html' ? '&nbsp;&nbsp;&nbsp;&nbsp;' : ' ';
+ }
+
// `parts_newline` requires `clause_newline`
$options['parts_newline'] &= $options['clause_newline'];
@@ -112,7 +116,7 @@ class Formatter
*
* @var string
*/
- 'indentation' => ' ',
+ 'indentation' => null,
/*
* Whether comments should be removed or not.
@@ -379,12 +383,16 @@ class Formatter
}
// The options of a clause should stay on the same line and everything that follows.
- if (($this->options['parts_newline'])
- && (!$formattedOptions)
- && (empty(self::$INLINE_CLAUSES[$lastClause]))
- && (($curr->type !== Token::TYPE_KEYWORD)
- || (($curr->type === Token::TYPE_KEYWORD)
- && ($curr->flags & Token::FLAG_KEYWORD_FUNCTION)))
+ if ($this->options['parts_newline']
+ && !$formattedOptions
+ && empty(self::$INLINE_CLAUSES[$lastClause])
+ && (
+ $curr->type !== Token::TYPE_KEYWORD
+ || (
+ $curr->type === Token::TYPE_KEYWORD
+ && $curr->flags & Token::FLAG_KEYWORD_FUNCTION
+ )
+ )
) {
$formattedOptions = true;
$lineEnded = true;
@@ -393,7 +401,7 @@ class Formatter
// Checking if this clause ended.
if ($tmp = static::isClause($curr)) {
- if (($tmp == 2) || ($this->options['clause_newline'])) {
+ if ($tmp == 2 || $this->options['clause_newline']) {
$lineEnded = true;
if ($this->options['parts_newline']) {
--$indent;
@@ -402,24 +410,26 @@ class Formatter
}
// Indenting BEGIN ... END blocks.
- if (($prev->type === Token::TYPE_KEYWORD) && ($prev->value === 'BEGIN')) {
+ if ($prev->type === Token::TYPE_KEYWORD && $prev->value === 'BEGIN') {
$lineEnded = true;
array_push($blocksIndentation, $indent);
++$indent;
- } elseif (($curr->type === Token::TYPE_KEYWORD) && ($curr->value === 'END')) {
+ } elseif ($curr->type === Token::TYPE_KEYWORD && $curr->value === 'END') {
$lineEnded = true;
$indent = array_pop($blocksIndentation);
}
// Formatting fragments delimited by comma.
- if (($prev->type === Token::TYPE_OPERATOR) && ($prev->value === ',')) {
+ if ($prev->type === Token::TYPE_OPERATOR && $prev->value === ',') {
// Fragments delimited by a comma are broken into multiple
// pieces only if the clause is not inlined or this fragment
// is between brackets that are on new line.
- if (((empty(self::$INLINE_CLAUSES[$lastClause]))
- && !$shortGroup
- && ($this->options['parts_newline']))
- || (end($blocksLineEndings) === true)
+ if (end($blocksLineEndings) === true
+ || (
+ empty(self::$INLINE_CLAUSES[$lastClause])
+ && !$shortGroup
+ && $this->options['parts_newline']
+ )
) {
$lineEnded = true;
}
@@ -428,7 +438,7 @@ class Formatter
// Handling brackets.
// Brackets are indented only if the length of the fragment between
// them is longer than 30 characters.
- if (($prev->type === Token::TYPE_OPERATOR) && ($prev->value === '(')) {
+ if ($prev->type === Token::TYPE_OPERATOR && $prev->value === '(') {
array_push($blocksIndentation, $indent);
$shortGroup = true;
if (static::getGroupLength($list) > 30) {
@@ -437,7 +447,7 @@ class Formatter
$shortGroup = false;
}
array_push($blocksLineEndings, $lineEnded);
- } elseif (($curr->type === Token::TYPE_OPERATOR) && ($curr->value === ')')) {
+ } elseif ($curr->type === Token::TYPE_OPERATOR && $curr->value === ')') {
$indent = array_pop($blocksIndentation);
$lineEnded |= array_pop($blocksLineEndings);
$shortGroup = false;
@@ -467,14 +477,13 @@ class Formatter
} else {
// If the line ended there is no point in adding whitespaces.
// Also, some tokens do not have spaces before or after them.
- if (!((($prev->type === Token::TYPE_OPERATOR) && (($prev->value === '.') || ($prev->value === '(')))
+ if (!(($prev->type === Token::TYPE_OPERATOR && ($prev->value === '.' || $prev->value === '('))
// No space after . (
- || (($curr->type === Token::TYPE_OPERATOR) && (($curr->value === '.') || ($curr->value === ',')
- || ($curr->value === '(') || ($curr->value === ')')))
+ || ($curr->type === Token::TYPE_OPERATOR && ($curr->value === '.' || $curr->value === ',' || $curr->value === '(' || $curr->value === ')'))
// No space before . , ( )
- || (($curr->type === Token::TYPE_DELIMITER)) && (mb_strlen($curr->value, 'UTF-8') < 2))
+ || $curr->type === Token::TYPE_DELIMITER && mb_strlen($curr->value, 'UTF-8') < 2)
// A space after delimiters that are longer than 2 characters.
- || ($prev->value === 'DELIMITER')
+ || $prev->value === 'DELIMITER'
) {
$ret .= ' ';
}
@@ -524,8 +533,8 @@ class Formatter
$text = $token->token;
foreach ($this->options['formats'] as $format) {
- if (($token->type === $format['type'])
- && (($token->flags & $format['flags']) === $format['flags'])
+ if ($token->type === $format['type']
+ && ($token->flags & $format['flags']) === $format['flags']
) {
// Running transformation function.
if (!empty($format['function'])) {
@@ -626,11 +635,14 @@ class Formatter
*/
public static function isClause($token)
{
- if ((($token->type === Token::TYPE_NONE) && (strtoupper($token->token) === 'DELIMITER'))
- || (($token->type === Token::TYPE_KEYWORD) && (isset(Parser::$STATEMENT_PARSERS[$token->value])))
+ if (
+ ($token->type === Token::TYPE_KEYWORD && isset(Parser::$STATEMENT_PARSERS[$token->value]))
+ || ($token->type === Token::TYPE_NONE && strtoupper($token->token) === 'DELIMITER')
) {
return 2;
- } elseif (($token->type === Token::TYPE_KEYWORD) && (isset(Parser::$KEYWORD_PARSERS[$token->value]))) {
+ } elseif (
+ $token->type === Token::TYPE_KEYWORD && isset(Parser::$KEYWORD_PARSERS[$token->value])
+ ) {
return 1;
}
diff --git a/tests/Parser/SelectStatementTest.php b/tests/Parser/SelectStatementTest.php
index bbfc926..79440a1 100644
--- a/tests/Parser/SelectStatementTest.php
+++ b/tests/Parser/SelectStatementTest.php
@@ -35,7 +35,9 @@ class SelectStatementTest extends TestCase
array('parser/parseSelect8'),
array('parser/parseSelect9'),
array('parser/parseSelect10'),
+ array('parser/parseSelect11'),
array('parser/parseSelectErr1'),
+ array('parser/parseSelectErr2'),
array('parser/parseSelectNested'),
array('parser/parseSelectCase1'),
array('parser/parseSelectCase2'),
diff --git a/tests/bootstrap.php b/tests/TestCase.php
index d37e4c4..ab0ecbc 100644
--- a/tests/bootstrap.php
+++ b/tests/TestCase.php
@@ -8,8 +8,7 @@ namespace SqlParser\Tests;
use SqlParser\Lexer;
use SqlParser\Parser;
-
-require_once 'vendor/autoload.php';
+use SqlParser\TokensList;
$GLOBALS['lang'] = 'en';
diff --git a/tests/Utils/CLITest.php b/tests/Utils/CLITest.php
index 3f5796d..a97d98f 100644
--- a/tests/Utils/CLITest.php
+++ b/tests/Utils/CLITest.php
@@ -29,17 +29,17 @@ class CLITest extends TestCase
return array(
array(
array('q' => 'SELECT 1'),
- "\x1b[35mSELECT\n \x1b[92m1\x1b[0m\n",
+ "\x1b[35mSELECT\n \x1b[92m1\x1b[0m\n",
0,
),
array(
array('query' => 'SELECT 1'),
- "\x1b[35mSELECT\n \x1b[92m1\x1b[0m\n",
+ "\x1b[35mSELECT\n \x1b[92m1\x1b[0m\n",
0,
),
array(
array('q' => 'SELECT /* comment */ 1 /* other */', 'f' => 'text'),
- "SELECT\n /* comment */ 1 /* other */\n",
+ "SELECT\n /* comment */ 1 /* other */\n",
0,
),
array(
@@ -50,7 +50,7 @@ class CLITest extends TestCase
array(
array('q' => 'SELECT 1', 'f' => 'html'),
'<span class="sql-reserved">SELECT</span>' . '<br/>' .
- ' <span class="sql-number">1</span>' . "\n",
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-number">1</span>' . "\n",
0,
),
array(
diff --git a/tests/Utils/FormatterTest.php b/tests/Utils/FormatterTest.php
index 1e03d17..15e6336 100644
--- a/tests/Utils/FormatterTest.php
+++ b/tests/Utils/FormatterTest.php
@@ -22,6 +22,7 @@ class FormatTest extends TestCase
->willReturn(array(
'type' => 'text',
'line_ending' => null,
+ 'indentation' => null,
'clause_newline' => null,
'parts_newline' => null,
));
@@ -33,6 +34,7 @@ class FormatTest extends TestCase
$expectedOptions = array(
'type' => 'test-type',
'line_ending' => '<br>',
+ 'indentation' => ' ',
'clause_newline' => null,
'parts_newline' => 0,
'formats' => $expected,
@@ -244,30 +246,30 @@ class FormatTest extends TestCase
array(
'SELECT 1',
'<span class="sql-reserved">SELECT</span>' . '<br/>' .
- ' <span class="sql-number">1</span>',
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-number">1</span>',
array('type' => 'html'),
),
array(
'SELECT 1 # Comment',
'<span class="sql-reserved">SELECT</span>' . '<br/>' .
- ' <span class="sql-number">1</span> <span class="sql-comment"># Comment' . "\n" .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-number">1</span> <span class="sql-comment"># Comment' . "\n" .
'</span>',
array('type' => 'html'),
),
array(
'SELECT HEX("1")',
'<span class="sql-reserved">SELECT</span>' . '<br/>' .
- ' <span class="sql-keyword">HEX</span>(<span class="sql-string">"1"</span>)',
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-keyword">HEX</span>(<span class="sql-string">"1"</span>)',
array('type' => 'html'),
),
array(
'SELECT * FROM foo WHERE bar=1',
'<span class="sql-reserved">SELECT</span>' . '<br/>' .
- ' *' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;*' . '<br/>' .
'<span class="sql-reserved">FROM</span>' . '<br/>' .
- ' foo' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;foo' . '<br/>' .
'<span class="sql-reserved">WHERE</span>' . '<br/>' .
- ' bar = <span class="sql-number">1</span>',
+ '&nbsp;&nbsp;&nbsp;&nbsp;bar = <span class="sql-number">1</span>',
array('type' => 'html'),
),
array(
@@ -276,9 +278,9 @@ class FormatTest extends TestCase
'<span class="sql-reserved">PROCEDURE</span> SPTEST()' . '<br/>' .
'<span class="sql-keyword">BEGIN</span>' . '<br/>' .
'<span class="sql-reserved">FROM</span>' . '<br/>' .
- ' a' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;a' . '<br/>' .
'<span class="sql-reserved">SELECT</span>' . '<br/>' .
- ' *;' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;*;' . '<br/>' .
'<span class="sql-keyword">END</span>',
array('type' => 'html'),
),
@@ -286,7 +288,7 @@ class FormatTest extends TestCase
'INSERT INTO foo VALUES (0, 0, 0), (1, 1, 1)',
'<span class="sql-reserved">INSERT</span>' . '<br/>' .
'<span class="sql-reserved">INTO</span>' . '<br/>' .
- ' foo' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;foo' . '<br/>' .
'<span class="sql-reserved">VALUES</span>' .
'(<span class="sql-number">0</span>, <span class="sql-number">0</span>, <span class="sql-number">0</span>),' .
'(<span class="sql-number">1</span>, <span class="sql-number">1</span>, <span class="sql-number">1</span>)',
@@ -294,38 +296,38 @@ class FormatTest extends TestCase
),
array(
'SELECT 1',
- "\x1b[35mSELECT\n \x1b[92m1\x1b[0m",
+ "\x1b[35mSELECT\n \x1b[92m1\x1b[0m",
array('type' => 'cli'),
),
array(
'SELECT "Text" AS BAR',
- "\x1b[35mSELECT\n \x1b[91m\"Text\" \x1b[35mAS \x1b[39mBAR\x1b[0m",
+ "\x1b[35mSELECT\n \x1b[91m\"Text\" \x1b[35mAS \x1b[39mBAR\x1b[0m",
array('type' => 'cli'),
),
array(
'SELECT coditm AS Item, descripcion AS Descripcion, contenedores AS Contenedores, IF(suspendido = 1, Si, NO) AS Suspendido FROM `DW_articulos` WHERE superado = 0',
'<span class="sql-reserved">SELECT</span>' . '<br/>' .
- ' coditm <span class="sql-reserved">AS</span> Item,' . '<br/>' .
- ' descripcion <span class="sql-reserved">AS</span> Descripcion,' . '<br/>' .
- ' contenedores <span class="sql-reserved">AS</span> Contenedores,' . '<br/>' .
- ' <span class="sql-reserved">IF</span>(suspendido = <span class="sql-number">1</span>, Si, <span class="sql-keyword">NO</span>) <span class="sql-reserved">AS</span> Suspendido' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;coditm <span class="sql-reserved">AS</span> Item,' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;descripcion <span class="sql-reserved">AS</span> Descripcion,' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;contenedores <span class="sql-reserved">AS</span> Contenedores,' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-reserved">IF</span>(suspendido = <span class="sql-number">1</span>, Si, <span class="sql-keyword">NO</span>) <span class="sql-reserved">AS</span> Suspendido' . '<br/>' .
'<span class="sql-reserved">FROM</span>' . '<br/>' .
- ' <span class="sql-variable">`DW_articulos`</span>' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-variable">`DW_articulos`</span>' . '<br/>' .
'<span class="sql-reserved">WHERE</span>' . '<br/>' .
- ' superado = <span class="sql-number">0</span>',
+ '&nbsp;&nbsp;&nbsp;&nbsp;superado = <span class="sql-number">0</span>',
array('type' => 'html'),
),
array(
'SELECT 1 -- comment',
'<span class="sql-reserved">SELECT</span>' . '<br/>' .
- ' <span class="sql-number">1</span> <span class="sql-comment">-- comment' . "\n" .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-number">1</span> <span class="sql-comment">-- comment' . "\n" .
'</span>',
array('type' => 'html'),
),
array(
'SELECT 1 -- comment',
'<span class="sql-reserved">SELECT</span>' . '<br/>' .
- ' <span class="sql-number">1</span>',
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-number">1</span>',
array('type' => 'html', 'remove_comments' => true),
),
array(
@@ -337,22 +339,26 @@ class FormatTest extends TestCase
' `query` text NOT NULL,' . "\n" .
' PRIMARY KEY (`id`)' . "\n",
'<span class="sql-reserved">CREATE</span> <span class="sql-reserved">TABLE</span> <span class="sql-reserved">IF NOT EXISTS</span> <span class="sql-variable">`pma__bookmark`</span>(' . '<br/>' .
- ' <span class="sql-variable">`id`</span> <span class="sql-reserved">INT</span>(<span class="sql-number">11</span>) <span class="sql-reserved">NOT NULL</span> <span class="sql-keyword">AUTO_INCREMENT</span>,' . '<br/>' .
- ' <span class="sql-variable">`dbase`</span> <span class="sql-reserved">VARCHAR</span>(<span class="sql-number">255</span>) <span class="sql-reserved">NOT NULL</span> <span class="sql-reserved">DEFAULT</span> <span class="sql-string">""</span>,' . '<br/>' .
- ' <span class="sql-variable">`user`</span> <span class="sql-reserved">VARCHAR</span>(<span class="sql-number">255</span>) <span class="sql-reserved">NOT NULL</span> <span class="sql-reserved">DEFAULT</span> <span class="sql-string">""</span>,' . '<br/>' .
- ' <span class="sql-variable">`label`</span> <span class="sql-reserved">VARCHAR</span>(<span class="sql-number">255</span>) <span class="sql-reserved">COLLATE</span> utf8_general_ci <span class="sql-reserved">NOT NULL</span> <span class="sql-reserved">DEFAULT</span> <span class="sql-string">""</span>,' . '<br/>' .
- ' <span class="sql-variable">`query`</span> <span class="sql-keyword">TEXT</span> <span class="sql-reserved">NOT NULL</span>,' . '<br/>' .
- ' <span class="sql-reserved">PRIMARY KEY</span>(<span class="sql-variable">`id`</span>)',
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-variable">`id`</span> <span class="sql-reserved">INT</span>(<span class="sql-number">11</span>) <span class="sql-reserved">NOT NULL</span> <span class="sql-keyword">AUTO_INCREMENT</span>,' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-variable">`dbase`</span> <span class="sql-reserved">VARCHAR</span>(<span class="sql-number">255</span>) <span class="sql-reserved">NOT NULL</span> <span class="sql-reserved">DEFAULT</span> <span class="sql-string">""</span>,' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-variable">`user`</span> <span class="sql-reserved">VARCHAR</span>(<span class="sql-number">255</span>) <span class="sql-reserved">NOT NULL</span> <span class="sql-reserved">DEFAULT</span> <span class="sql-string">""</span>,' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-variable">`label`</span> <span class="sql-reserved">VARCHAR</span>(<span class="sql-number">255</span>) <span class="sql-reserved">COLLATE</span> utf8_general_ci <span class="sql-reserved">NOT NULL</span> <span class="sql-reserved">DEFAULT</span> <span class="sql-string">""</span>,' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-variable">`query`</span> <span class="sql-keyword">TEXT</span> <span class="sql-reserved">NOT NULL</span>,' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-reserved">PRIMARY KEY</span>(<span class="sql-variable">`id`</span>)',
array('type' => 'html'),
),
array(
"select '<s>xss' from `<s>xss` , <s>nxss /*s<s>xss*/",
- '<span class="sql-reserved">SELECT</span><br/> <span class="sql-string">\'&lt;s&gt;xss\'</span><br/><span class="sql-reserved">FROM</span><br/> <span class="sql-variable">`&lt;s&gt;xss`</span>,<br/> &lt; s &gt; nxss <span class="sql-comment">/*s&lt;s&gt;xss*/</span>',
+ '<span class="sql-reserved">SELECT</span>' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-string">\'&lt;s&gt;xss\'</span>' . '<br/>' .
+ '<span class="sql-reserved">FROM</span>' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;<span class="sql-variable">`&lt;s&gt;xss`</span>,' . '<br/>' .
+ '&nbsp;&nbsp;&nbsp;&nbsp;&lt; s &gt; nxss <span class="sql-comment">/*s&lt;s&gt;xss*/</span>',
array('type' => 'html'),
),
array(
"select 'text\x1b[33mcolor-inj' from tbl",
- "\x1b[35mSELECT\n \x1b[91m'text\\x1B[33mcolor-inj'\n\x1b[35mFROM\n \x1b[39mtbl\x1b[0m",
+ "\x1b[35mSELECT\n \x1b[91m'text\\x1B[33mcolor-inj'\n\x1b[35mFROM\n \x1b[39mtbl\x1b[0m",
array('type' => 'cli'),
),
);
diff --git a/tests/data/parser/parseSelect11.in b/tests/data/parser/parseSelect11.in
new file mode 100644
index 0000000..99f01a8
--- /dev/null
+++ b/tests/data/parser/parseSelect11.in
@@ -0,0 +1 @@
+SELECT 1 AND NOT 1
diff --git a/tests/data/parser/parseSelect11.out b/tests/data/parser/parseSelect11.out
new file mode 100644
index 0000000..2f08592
--- /dev/null
+++ b/tests/data/parser/parseSelect11.out
@@ -0,0 +1,4 @@
+a:4:{s:5:"query";s:19:"SELECT 1 AND NOT 1
+";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:19:"SELECT 1 AND NOT 1
+";s:3:"len";i:19;s:4:"last";i:19;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:11:{i:0;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:0;}i:1;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:6;}i:2;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"1";s:5:"value";i:1;s:4:"type";i:6;s:5:"flags";i:0;s:8:"position";i:7;}i:3;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:8;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"AND";s:5:"value";s:3:"AND";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:9;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:12;}i:6;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"NOT";s:5:"value";s:3:"NOT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:13;}i:7;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:16;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"1";s:5:"value";i:1;s:4:"type";i:6;s:5:"flags";i:0;s:8:"position";i:17;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"
+";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:18;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";N;s:5:"value";N;s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";N;}}s:5:"count";i:11;s:3:"idx";i:11;}s:9:"delimiter";s:1:";";s:12:"delimiterLen";i:1;s:6:"errors";a:0:{}}s:6:"parser";O:16:"SqlParser\Parser":5:{s:4:"list";r:8;s:6:"strict";b:0;s:6:"errors";a:0:{}s:10:"statements";a:1:{i:0;O:36:"SqlParser\Statements\SelectStatement":16:{s:4:"expr";a:1:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:11:"1 AND NOT 1";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}s:4:"from";a:0:{}s:9:"partition";N;s:5:"where";N;s:5:"group";N;s:6:"having";N;s:5:"order";N;s:5:"limit";N;s:9:"procedure";N;s:4:"into";N;s:4:"join";N;s:5:"union";a:0:{}s:11:"end_options";N;s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:9;}}s:8:"brackets";i:0;}s:6:"errors";a:2:{s:5:"lexer";a:0:{}s:6:"parser";a:0:{}}} \ No newline at end of file
diff --git a/tests/data/parser/parseSelectErr2.in b/tests/data/parser/parseSelectErr2.in
new file mode 100644
index 0000000..494d5b7
--- /dev/null
+++ b/tests/data/parser/parseSelectErr2.in
@@ -0,0 +1 @@
+select * from foobar where foo = @
diff --git a/tests/data/parser/parseSelectErr2.out b/tests/data/parser/parseSelectErr2.out
new file mode 100644
index 0000000..cece70e
--- /dev/null
+++ b/tests/data/parser/parseSelectErr2.out
@@ -0,0 +1,4 @@
+a:4:{s:5:"query";s:35:"select * from foobar where foo = @
+";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:35:"select * from foobar where foo = @
+";s:3:"len";i:35;s:4:"last";i:35;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:16:{i:0;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"select";s:5:"value";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:0;}i:1;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:6;}i:2;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"*";s:5:"value";s:1:"*";s:4:"type";i:2;s:5:"flags";i:1;s:8:"position";i:7;}i:3;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:8;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"from";s:5:"value";s:4:"FROM";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:9;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:13;}i:6;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"foobar";s:5:"value";s:6:"foobar";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:14;}i:7;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:20;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"where";s:5:"value";s:5:"WHERE";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:21;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:26;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"foo";s:5:"value";s:3:"foo";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:27;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:30;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"=";s:5:"value";s:1:"=";s:4:"type";i:2;s:5:"flags";i:2;s:8:"position";i:31;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:32;}i:14;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"@";s:5:"value";s:0:"";s:4:"type";i:8;s:5:"flags";i:1;s:8:"position";i:33;}i:15;O:15:"SqlParser\Token":5:{s:5:"token";N;s:5:"value";N;s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";N;}}s:5:"count";i:16;s:3:"idx";i:16;}s:9:"delimiter";s:1:";";s:12:"delimiterLen";i:1;s:6:"errors";a:0:{}}s:6:"parser";O:16:"SqlParser\Parser":5:{s:4:"list";r:8;s:6:"strict";b:0;s:6:"errors";a:0:{}s:10:"statements";a:1:{i:0;O:36:"SqlParser\Statements\SelectStatement":16:{s:4:"expr";a:1:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:1:"*";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}s:4:"from";a:1:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:6:"foobar";s:6:"column";N;s:4:"expr";s:6:"foobar";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}s:9:"partition";N;s:5:"where";a:1:{i:0;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:2:{i:0;s:3:"foo";i:1;s:0:"";}s:10:"isOperator";b:0;s:4:"expr";s:7:"foo = @";}}s:5:"group";N;s:6:"having";N;s:5:"order";N;s:5:"limit";N;s:9:"procedure";N;s:4:"into";N;s:4:"join";N;s:5:"union";a:0:{}s:11:"end_options";N;s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:14;}}s:8:"brackets";i:0;}s:6:"errors";a:2:{s:5:"lexer";a:1:{i:0;a:4:{i:0;s:27:"Variable name was expected.";i:1;s:1:"
+";i:2;i:34;i:3;i:0;}}s:6:"parser";a:0:{}}} \ No newline at end of file
diff --git a/tools/ContextGenerator.php b/tools/ContextGenerator.php
index 5876b86..43ea315 100644
--- a/tools/ContextGenerator.php
+++ b/tools/ContextGenerator.php
@@ -193,7 +193,7 @@ class ContextGenerator
if ($i == 0) {
$ret .= str_repeat(' ', $spaces);
}
- $ret .= "'" . $word . "' => " . $type . ', ';
+ $ret .= sprintf('\'%s\' => %s, ', $word, $type);
if (++$i == $count) {
$ret .= "\n";
$i = 0;