summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--src/Components/JoinKeyword.php20
-rw-r--r--src/Context.php10
-rw-r--r--src/Contexts/ContextMySql50000.php15
-rw-r--r--src/Contexts/ContextMySql50100.php15
-rw-r--r--src/Contexts/ContextMySql50500.php15
-rw-r--r--src/Contexts/ContextMySql50600.php15
-rw-r--r--src/Contexts/ContextMySql50700.php15
-rw-r--r--src/Lexer.php57
-rw-r--r--src/Parser.php22
-rw-r--r--src/Statements/SelectStatement.php49
-rw-r--r--src/Token.php12
-rw-r--r--tests/Lexer/LexerTest.php2
-rw-r--r--tests/Parser/SelectStatementTest.php7
-rw-r--r--tests/data/lexer/lexLabel1.in11
-rw-r--r--tests/data/lexer/lexLabel1.out31
-rw-r--r--tests/data/lexer/lexLabel2.in11
-rw-r--r--tests/data/lexer/lexLabel2.out31
-rw-r--r--tests/data/parser/parseSelect7.out4
-rw-r--r--tests/data/parser/parseSelectJoinCross.in4
-rw-r--r--tests/data/parser/parseSelectJoinCross.out10
-rw-r--r--tests/data/parser/parseSelectJoinMultiple.in2
-rw-r--r--tests/data/parser/parseSelectJoinMultiple.out4
-rw-r--r--tests/data/parser/parseSelectJoinNatural.in3
-rw-r--r--tests/data/parser/parseSelectJoinNatural.out7
-rw-r--r--tests/data/parser/parseSelectJoinNaturalLeft.in3
-rw-r--r--tests/data/parser/parseSelectJoinNaturalLeft.out7
-rw-r--r--tests/data/parser/parseSelectJoinNaturalLeftOuter.in1
-rw-r--r--tests/data/parser/parseSelectJoinNaturalLeftOuter.out1
-rw-r--r--tests/data/parser/parseSelectJoinNaturalRight.in1
-rw-r--r--tests/data/parser/parseSelectJoinNaturalRight.out4
-rw-r--r--tests/data/parser/parseSelectJoinNaturalRightOuter.in1
-rw-r--r--tests/data/parser/parseSelectJoinNaturalRightOuter.out1
-rw-r--r--tools/contexts/_common.txt6
34 files changed, 338 insertions, 63 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 92a1668..236a79b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,11 @@
## [Unreleased]
+## [3.4.11] - 2016-10-25
+
* Fixed parsing of ON UPDATE option in field definition of TIMESTAMP type with precision
+* Fixed parsing of NATURAL JOIN, CROSS JOIN and related joins.
+* Fixed parsing of BEGIN/END labels.
## [3.4.10] - 2016-10-03
diff --git a/src/Components/JoinKeyword.php b/src/Components/JoinKeyword.php
index 7062783..548a64e 100644
--- a/src/Components/JoinKeyword.php
+++ b/src/Components/JoinKeyword.php
@@ -30,6 +30,7 @@ class JoinKeyword extends Component
* @var array
*/
public static $JOINS = array(
+ 'CROSS JOIN' => 'CROSS',
'FULL JOIN' => 'FULL',
'FULL OUTER JOIN' => 'FULL',
'INNER JOIN' => 'INNER',
@@ -38,6 +39,12 @@ class JoinKeyword extends Component
'LEFT OUTER JOIN' => 'LEFT',
'RIGHT JOIN' => 'RIGHT',
'RIGHT OUTER JOIN' => 'RIGHT',
+ 'NATURAL JOIN' => 'NATURAL',
+ 'NATURAL LEFT JOIN' => 'NATURAL LEFT',
+ 'NATURAL LEFT JOIN' => 'NATURAL LEFT',
+ 'NATURAL RIGHT JOIN' => 'NATURAL RIGHT',
+ 'NATURAL LEFT OUTER JOIN' => 'NATURAL LEFT OUTER',
+ 'NATURAL RIGHT OUTER JOIN' => 'NATURAL RIGHT OUTER',
'STRAIGHT_JOIN' => 'STRAIGHT',
);
@@ -147,8 +154,17 @@ class JoinKeyword extends Component
} elseif ($token->value === 'USING') {
$state = 4;
} else {
- /* Next clause is starting */
- break;
+ if (($token->type === Token::TYPE_KEYWORD)
+ && (!empty(static::$JOINS[$token->value]))
+ ) {
+ $ret[] = $expr;
+ $expr = new JoinKeyword();
+ $expr->type = static::$JOINS[$token->value];
+ $state = 1;
+ } else {
+ /* Next clause is starting */
+ break;
+ }
}
}
} elseif ($state === 3) {
diff --git a/src/Context.php b/src/Context.php
index 0bdc696..3685857 100644
--- a/src/Context.php
+++ b/src/Context.php
@@ -30,6 +30,16 @@ abstract class Context
const KEYWORD_MAX_LENGTH = 30;
/**
+ * The maximum length of a label.
+ *
+ * @see static::$TOKEN_LABEL
+ * Ref: https://dev.mysql.com/doc/refman/5.7/en/statement-labels.html
+ *
+ * @var int
+ */
+ const LABEL_MAX_LENGTH = 16;
+
+ /**
* The maximum length of an operator.
*
* @see static::$TOKEN_OPERATOR
diff --git a/src/Contexts/ContextMySql50000.php b/src/Contexts/ContextMySql50000.php
index 4931faa..f8afd18 100644
--- a/src/Contexts/ContextMySql50000.php
+++ b/src/Contexts/ContextMySql50000.php
@@ -145,20 +145,21 @@ class ContextMySql50000 extends Context
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
'UNION ALL' => 7,
- 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7,
- 'RIGHT JOIN' => 7,
+ 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7,
+ 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
'LINEAR HASH' => 7,
- 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
- 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
+ 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
+ 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,
'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7,
- 'START TRANSACTION' => 7,
- 'SELECT TRANSACTION' => 7,
+ 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7,
+ 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7,
'DEFAULT CHARACTER SET' => 7,
- 'WITH CONSISTENT SNAPSHOT' => 7,
+ 'NATURAL LEFT OUTER JOIN' => 7,
+ 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7,
'BIT' => 9, 'XML' => 9,
'ENUM' => 9, 'JSON' => 9, 'TEXT' => 9,
diff --git a/src/Contexts/ContextMySql50100.php b/src/Contexts/ContextMySql50100.php
index a547e64..dd2b677 100644
--- a/src/Contexts/ContextMySql50100.php
+++ b/src/Contexts/ContextMySql50100.php
@@ -159,20 +159,21 @@ class ContextMySql50100 extends Context
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
'UNION ALL' => 7,
- 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7,
- 'RIGHT JOIN' => 7,
+ 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7,
+ 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
'LINEAR HASH' => 7,
- 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
- 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
+ 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
+ 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,
'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7,
- 'START TRANSACTION' => 7,
- 'SELECT TRANSACTION' => 7,
+ 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7,
+ 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7,
'DEFAULT CHARACTER SET' => 7,
- 'WITH CONSISTENT SNAPSHOT' => 7,
+ 'NATURAL LEFT OUTER JOIN' => 7,
+ 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7,
'BIT' => 9, 'XML' => 9,
'ENUM' => 9, 'JSON' => 9, 'TEXT' => 9,
diff --git a/src/Contexts/ContextMySql50500.php b/src/Contexts/ContextMySql50500.php
index a15744a..02acdac 100644
--- a/src/Contexts/ContextMySql50500.php
+++ b/src/Contexts/ContextMySql50500.php
@@ -163,20 +163,21 @@ class ContextMySql50500 extends Context
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
'UNION ALL' => 7,
- 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7,
- 'RIGHT JOIN' => 7,
+ 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7,
+ 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
'LINEAR HASH' => 7,
- 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
- 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
+ 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
+ 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,
'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7,
- 'START TRANSACTION' => 7,
- 'SELECT TRANSACTION' => 7,
+ 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7,
+ 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7,
'DEFAULT CHARACTER SET' => 7,
- 'WITH CONSISTENT SNAPSHOT' => 7,
+ 'NATURAL LEFT OUTER JOIN' => 7,
+ 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7,
'BIT' => 9, 'XML' => 9,
'ENUM' => 9, 'JSON' => 9, 'TEXT' => 9,
diff --git a/src/Contexts/ContextMySql50600.php b/src/Contexts/ContextMySql50600.php
index 7a0cf56..1143978 100644
--- a/src/Contexts/ContextMySql50600.php
+++ b/src/Contexts/ContextMySql50600.php
@@ -169,20 +169,21 @@ class ContextMySql50600 extends Context
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
'UNION ALL' => 7,
- 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7,
- 'RIGHT JOIN' => 7,
+ 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7,
+ 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
'LINEAR HASH' => 7,
- 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
- 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
+ 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
+ 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,
'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7,
- 'START TRANSACTION' => 7,
- 'SELECT TRANSACTION' => 7,
+ 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7,
+ 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7,
'DEFAULT CHARACTER SET' => 7,
- 'WITH CONSISTENT SNAPSHOT' => 7,
+ 'NATURAL LEFT OUTER JOIN' => 7,
+ 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7,
'BIT' => 9, 'XML' => 9,
'ENUM' => 9, 'JSON' => 9, 'TEXT' => 9,
diff --git a/src/Contexts/ContextMySql50700.php b/src/Contexts/ContextMySql50700.php
index 8682032..04f410b 100644
--- a/src/Contexts/ContextMySql50700.php
+++ b/src/Contexts/ContextMySql50700.php
@@ -175,20 +175,21 @@ class ContextMySql50700 extends Context
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
'UNION ALL' => 7,
- 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7,
- 'RIGHT JOIN' => 7,
+ 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7,
+ 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
'LINEAR HASH' => 7,
- 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
- 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
+ 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'NATURAL JOIN' => 7,
+ 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7,
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7, 'UNION DISTINCT' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'FULL OUTER JOIN' => 7,
'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7,
'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7,
- 'START TRANSACTION' => 7,
- 'SELECT TRANSACTION' => 7,
+ 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7,
+ 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7,
'DEFAULT CHARACTER SET' => 7,
- 'WITH CONSISTENT SNAPSHOT' => 7,
+ 'NATURAL LEFT OUTER JOIN' => 7,
+ 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7,
'BIT' => 9, 'XML' => 9,
'ENUM' => 9, 'JSON' => 9, 'TEXT' => 9,
diff --git a/src/Lexer.php b/src/Lexer.php
index 7fb2356..9de2a7a 100644
--- a/src/Lexer.php
+++ b/src/Lexer.php
@@ -76,7 +76,7 @@ class Lexer
'parseDelimiter', 'parseWhitespace', 'parseNumber',
'parseComment', 'parseOperator', 'parseBool', 'parseString',
- 'parseSymbol', 'parseKeyword', 'parseUnknown'
+ 'parseSymbol', 'parseKeyword', 'parseLabel', 'parseUnknown'
);
/**
@@ -442,6 +442,61 @@ class Lexer
}
/**
+ * Parses a label.
+ *
+ * @return Token
+ */
+ public function parseLabel()
+ {
+ $token = '';
+
+ /**
+ * Value to be returned.
+ *
+ * @var Token $ret
+ */
+ $ret = null;
+
+ /**
+ * The value of `$this->last` where `$token` ends in `$this->str`.
+ *
+ * @var int $iEnd
+ */
+ $iEnd = $this->last;
+
+ /**
+ * Whether last parsed character is a whitespace.
+ *
+ * @var bool $lastSpace
+ */
+ $lastSpace = false;
+
+ for ($j = 1; $j < Context::LABEL_MAX_LENGTH && $this->last < $this->len; ++$j, ++$this->last) {
+ // Composed keywords shouldn't have more than one whitespace between
+ // keywords.
+ if (Context::isWhitespace($this->str[$this->last])) {
+ if ($lastSpace) {
+ --$j; // The size of the keyword didn't increase.
+ continue;
+ } else {
+ $lastSpace = true;
+ }
+ } elseif ($this->str[$this->last] === ':') {
+ $token .= $this->str[$this->last];
+ $ret = new Token($token, Token::TYPE_LABEL);
+ $iEnd = $this->last;
+ break;
+ } else {
+ $lastSpace = false;
+ }
+ $token .= $this->str[$this->last];
+ }
+
+ $this->last = $iEnd;
+ return $ret;
+ }
+
+ /**
* Parses an operator.
*
* @return Token
diff --git a/src/Parser.php b/src/Parser.php
index 21e1b39..0d48a41 100644
--- a/src/Parser.php
+++ b/src/Parser.php
@@ -154,6 +154,10 @@ class Parser
'field' => 'tables',
'options' => array('parseField' => 'table'),
),
+ 'CROSS JOIN' => array(
+ 'class' => 'SqlParser\\Components\\JoinKeyword',
+ 'field' => 'join',
+ ),
'DROP' => array(
'class' => 'SqlParser\\Components\\ExpressionArray',
'field' => 'fields',
@@ -213,7 +217,23 @@ class Parser
'class' => 'SqlParser\\Components\\JoinKeyword',
'field' => 'join',
),
- 'STRAIGHT_JOIN' => array(
+ 'NATURAL JOIN' => array(
+ 'class' => 'SqlParser\\Components\\JoinKeyword',
+ 'field' => 'join',
+ ),
+ 'NATURAL LEFT JOIN' => array(
+ 'class' => 'SqlParser\\Components\\JoinKeyword',
+ 'field' => 'join',
+ ),
+ 'NATURAL RIGHT JOIN' => array(
+ 'class' => 'SqlParser\\Components\\JoinKeyword',
+ 'field' => 'join',
+ ),
+ 'NATURAL LEFT OUTER JOIN' => array(
+ 'class' => 'SqlParser\\Components\\JoinKeyword',
+ 'field' => 'join',
+ ),
+ 'NATURAL RIGHT OUTER JOIN' => array(
'class' => 'SqlParser\\Components\\JoinKeyword',
'field' => 'join',
),
diff --git a/src/Statements/SelectStatement.php b/src/Statements/SelectStatement.php
index 34a68c3..8ff0b45 100644
--- a/src/Statements/SelectStatement.php
+++ b/src/Statements/SelectStatement.php
@@ -82,30 +82,35 @@ class SelectStatement extends Statement
* @var array
*/
public static $CLAUSES = array(
- 'SELECT' => array('SELECT', 2),
+ 'SELECT' => array('SELECT', 2),
// Used for options.
- '_OPTIONS' => array('_OPTIONS', 1),
+ '_OPTIONS' => array('_OPTIONS', 1),
// Used for selected expressions.
- '_SELECT' => array('SELECT', 1),
- 'INTO' => array('INTO', 3),
- 'FROM' => array('FROM', 3),
- 'PARTITION' => array('PARTITION', 3),
-
- 'JOIN' => array('JOIN', 1),
- 'FULL JOIN' => array('FULL JOIN', 1),
- 'INNER JOIN' => array('INNER JOIN', 1),
- 'LEFT JOIN' => array('LEFT JOIN', 1),
- 'LEFT OUTER JOIN' => array('LEFT OUTER JOIN', 1),
- 'RIGHT JOIN' => array('RIGHT JOIN', 1),
- 'RIGHT OUTER JOIN' => array('RIGHT OUTER JOIN', 1),
-
- 'WHERE' => array('WHERE', 3),
- 'GROUP BY' => array('GROUP BY', 3),
- 'HAVING' => array('HAVING', 3),
- 'ORDER BY' => array('ORDER BY', 3),
- 'LIMIT' => array('LIMIT', 3),
- 'PROCEDURE' => array('PROCEDURE', 3),
- 'UNION' => array('UNION', 1),
+ '_SELECT' => array('SELECT', 1),
+ 'INTO' => array('INTO', 3),
+ 'FROM' => array('FROM', 3),
+ 'PARTITION' => array('PARTITION', 3),
+
+ 'JOIN' => array('JOIN', 1),
+ 'FULL JOIN' => array('FULL JOIN', 1),
+ 'INNER JOIN' => array('INNER JOIN', 1),
+ 'LEFT JOIN' => array('LEFT JOIN', 1),
+ 'LEFT OUTER JOIN' => array('LEFT OUTER JOIN', 1),
+ 'RIGHT JOIN' => array('RIGHT JOIN', 1),
+ 'RIGHT OUTER JOIN' => array('RIGHT OUTER JOIN', 1),
+ 'NATURAL JOIN' => array('NATURAL JOIN', 1),
+ 'NATURAL LEFT JOIN' => array('NATURAL LEFT JOIN', 1),
+ 'NATURAL RIGHT JOIN' => array('NATURAL RIGHT JOIN', 1),
+ 'NATURAL LEFT OUTER JOIN' => array('NATURAL LEFT OUTER JOIN', 1),
+ 'NATURAL RIGHT OUTER JOIN' => array('NATURAL RIGHT JOIN', 1),
+
+ 'WHERE' => array('WHERE', 3),
+ 'GROUP BY' => array('GROUP BY', 3),
+ 'HAVING' => array('HAVING', 3),
+ 'ORDER BY' => array('ORDER BY', 3),
+ 'LIMIT' => array('LIMIT', 3),
+ 'PROCEDURE' => array('PROCEDURE', 3),
+ 'UNION' => array('UNION', 1),
// These are available only when `UNION` is present.
// 'ORDER BY' => array('ORDER BY', 3),
// 'LIMIT' => array('LIMIT', 3),
diff --git a/src/Token.php b/src/Token.php
index 3181a44..e5001ef 100644
--- a/src/Token.php
+++ b/src/Token.php
@@ -119,6 +119,18 @@ class Token
*/
const TYPE_DELIMITER = 9;
+ /**
+ * Labels in LOOP statement, ITERATE statement etc.
+ * For example (only for begin label):
+ * begin_label: BEGIN [statement_list] END [end_label]
+ * begin_label: LOOP [statement_list] END LOOP [end_label]
+ * begin_label: REPEAT [statement_list] ... END REPEAT [end_label]
+ * begin_label: WHILE ... DO [statement_list] END WHILE [end_label]
+ *
+ * @var int
+ */
+ const TYPE_LABEL = 10;
+
// Flags that describe the tokens in more detail.
// All keywords must have flag 1 so `Context::isKeyword` method doesn't
// require strict comparison.
diff --git a/tests/Lexer/LexerTest.php b/tests/Lexer/LexerTest.php
index 9c22768..0bcd3f7 100644
--- a/tests/Lexer/LexerTest.php
+++ b/tests/Lexer/LexerTest.php
@@ -80,6 +80,8 @@ class LexerTest extends TestCase
array('lexer/lexSymbolErr3'),
array('lexer/lexSymbolUser'),
array('lexer/lexWhitespace'),
+ array('lexer/lexLabel1'),
+ array('lexer/lexLabel2'),
);
}
}
diff --git a/tests/Parser/SelectStatementTest.php b/tests/Parser/SelectStatementTest.php
index 1e9d726..0420c11 100644
--- a/tests/Parser/SelectStatementTest.php
+++ b/tests/Parser/SelectStatementTest.php
@@ -47,6 +47,13 @@ class SelectStatementTest extends TestCase
array('parser/parseSelectCaseErr3'),
array('parser/parseSelectCaseErr4'),
array('parser/parseSelectCaseErr5'),
+ array('parser/parseSelectJoinCross'),
+ array('parser/parseSelectJoinNatural'),
+ array('parser/parseSelectJoinNaturalLeft'),
+ array('parser/parseSelectJoinNaturalRight'),
+ array('parser/parseSelectJoinNaturalLeftOuter'),
+ array('parser/parseSelectJoinNaturalRightOuter'),
+ array('parser/parseSelectJoinMultiple'),
);
}
}
diff --git a/tests/data/lexer/lexLabel1.in b/tests/data/lexer/lexLabel1.in
new file mode 100644
index 0000000..41420e6
--- /dev/null
+++ b/tests/data/lexer/lexLabel1.in
@@ -0,0 +1,11 @@
+CREATE PROCEDURE doiterate(p1 INT)
+BEGIN
+ label1 : LOOP
+ SET p1 = p1 + 1;
+ IF p1 < 10 THEN
+ ITERATE label1;
+ END IF;
+ LEAVE label1;
+ END LOOP label1;
+ SET @x = p1;
+END \ No newline at end of file
diff --git a/tests/data/lexer/lexLabel1.out b/tests/data/lexer/lexLabel1.out
new file mode 100644
index 0000000..17d5996
--- /dev/null
+++ b/tests/data/lexer/lexLabel1.out
@@ -0,0 +1,31 @@
+a:4:{s:5:"query";s:187:"CREATE PROCEDURE doiterate(p1 INT)
+BEGIN
+ label1 : LOOP
+ SET p1 = p1 + 1;
+ IF p1 < 10 THEN
+ ITERATE label1;
+ END IF;
+ LEAVE label1;
+ END LOOP label1;
+ SET @x = p1;
+END";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:187:"CREATE PROCEDURE doiterate(p1 INT)
+BEGIN
+ label1 : LOOP
+ SET p1 = p1 + 1;
+ IF p1 < 10 THEN
+ ITERATE label1;
+ END IF;
+ LEAVE label1;
+ END LOOP label1;
+ SET @x = p1;
+END";s:3:"len";i:187;s:4:"last";i:187;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:73:{i:0;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"CREATE";s:5:"value";s:6:"CREATE";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:9:"PROCEDURE";s:5:"value";s:9:"PROCEDURE";s:4:"type";i:1;s:5:"flags";i:3;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:16;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:9:"doiterate";s:5:"value";s:9:"doiterate";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:17;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:26;}i:6;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:27;}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:29;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"INT";s:5:"value";s:3:"INT";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:30;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:33;}i:10;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:34;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"BEGIN";s:5:"value";s:5:"BEGIN";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:35;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:40;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"label1 :";s:5:"value";s:8:"label1 :";s:4:"type";i:10;s:5:"flags";i:0;s:8:"position";i:43;}i:14;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:51;}i:15;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"LOOP";s:5:"value";s:4:"LOOP";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:52;}i:16;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:56;}i:17;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"SET";s:5:"value";s:3:"SET";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:61;}i:18;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:64;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:65;}i:20;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:67;}i:21;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:68;}i:22;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:69;}i:23;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:70;}i:24;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:72;}i:25;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:73;}i:26;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:74;}i:27;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:75;}i:28;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:76;}i:29;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:77;}i:30;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"IF";s:5:"value";s:2:"IF";s:4:"type";i:1;s:5:"flags";i:35;s:8:"position";i:82;}i:31;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:84;}i:32;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:85;}i:33;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:87;}i:34;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:88;}i:35;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:89;}i:36;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"10";s:5:"value";i:10;s:4:"type";i:6;s:5:"flags";i:0;s:8:"position";i:90;}i:37;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:92;}i:38;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"THEN";s:5:"value";s:4:"THEN";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:93;}i:39;O:15:"SqlParser\Token":5:{s:5:"token";s:7:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:97;}i:40;O:15:"SqlParser\Token":5:{s:5:"token";s:7:"ITERATE";s:5:"value";s:7:"ITERATE";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:104;}i:41;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:111;}i:42;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"label1";s:5:"value";s:6:"label1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:112;}i:43;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:118;}i:44;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:119;}i:45;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"END";s:5:"value";s:3:"END";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:124;}i:46;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:127;}i:47;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"IF";s:5:"value";s:2:"IF";s:4:"type";i:1;s:5:"flags";i:35;s:8:"position";i:128;}i:48;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:130;}i:49;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:131;}i:50;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"LEAVE";s:5:"value";s:5:"LEAVE";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:136;}i:51;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:141;}i:52;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"label1";s:5:"value";s:6:"label1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:142;}i:53;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:148;}i:54;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:149;}i:55;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"END";s:5:"value";s:3:"END";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:152;}i:56;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:155;}i:57;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"LOOP";s:5:"value";s:4:"LOOP";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:156;}i:58;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:160;}i:59;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"label1";s:5:"value";s:6:"label1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:161;}i:60;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:167;}i:61;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:168;}i:62;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"SET";s:5:"value";s:3:"SET";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:171;}i:63;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:174;}i:64;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"@x";s:5:"value";s:1:"x";s:4:"type";i:8;s:5:"flags";i:1;s:8:"position";i:175;}i:65;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:177;}i:66;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:178;}i:67;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:179;}i:68;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:180;}i:69;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:182;}i:70;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:183;}i:71;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"END";s:5:"value";s:3:"END";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:184;}i:72;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:73;s:3:"idx";i:74;}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\CreateStatement":17:{s:4:"name";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:9:"doiterate";s:6:"column";N;s:4:"expr";s:9:"doiterate";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:13:"entityOptions";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:6:"fields";N;s:6:"select";N;s:4:"like";N;s:11:"partitionBy";N;s:13:"partitionsNum";N;s:14:"subpartitionBy";N;s:16:"subpartitionsNum";N;s:10:"partitions";N;s:5:"table";N;s:6:"return";N;s:10:"parameters";a:1:{i:0;O:40:"SqlParser\Components\ParameterDefinition":3:{s:4:"name";s:2:"p1";s:5:"inOut";N;s:4:"type";O:29:"SqlParser\Components\DataType":3:{s:4:"name";s:3:"INT";s:10:"parameters";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}}}}s:4:"body";a:62:{i:0;r:76;i:1;r:82;i:2;r:88;i:3;r:94;i:4;r:100;i:5;r:106;i:6;r:112;i:7;r:118;i:8;r:124;i:9;r:130;i:10;r:136;i:11;r:142;i:12;r:148;i:13;r:154;i:14;r:160;i:15;r:166;i:16;r:172;i:17;r:178;i:18;r:184;i:19;r:190;i:20;r:196;i:21;r:202;i:22;r:208;i:23;r:214;i:24;r:220;i:25;r:226;i:26;r:232;i:27;r:238;i:28;r:244;i:29;r:250;i:30;r:256;i:31;r:262;i:32;r:268;i:33;r:274;i:34;r:280;i:35;r:286;i:36;r:292;i:37;r:298;i:38;r:304;i:39;r:310;i:40;r:316;i:41;r:322;i:42;r:328;i:43;r:334;i:44;r:340;i:45;r:346;i:46;r:352;i:47;r:358;i:48;r:364;i:49;r:370;i:50;r:376;i:51;r:382;i:52;r:388;i:53;r:394;i:54;r:400;i:55;r:406;i:56;r:412;i:57;r:418;i:58;r:424;i:59;r:430;i:60;r:436;i:61;r:442;}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:1:{i:6;s:9:"PROCEDURE";}}s:5:"first";i:0;s:4:"last";i:73;}}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/lexer/lexLabel2.in b/tests/data/lexer/lexLabel2.in
new file mode 100644
index 0000000..3e98477
--- /dev/null
+++ b/tests/data/lexer/lexLabel2.in
@@ -0,0 +1,11 @@
+CREATE PROCEDURE doiterate(p1 INT)
+BEGIN
+ label1: LOOP
+ SET p1 = p1 + 1;
+ IF p1 < 10 THEN
+ ITERATE label1;
+ END IF;
+ LEAVE label1;
+ END LOOP label1;
+ SET @x = p1;
+END \ No newline at end of file
diff --git a/tests/data/lexer/lexLabel2.out b/tests/data/lexer/lexLabel2.out
new file mode 100644
index 0000000..b22d04b
--- /dev/null
+++ b/tests/data/lexer/lexLabel2.out
@@ -0,0 +1,31 @@
+a:4:{s:5:"query";s:186:"CREATE PROCEDURE doiterate(p1 INT)
+BEGIN
+ label1: LOOP
+ SET p1 = p1 + 1;
+ IF p1 < 10 THEN
+ ITERATE label1;
+ END IF;
+ LEAVE label1;
+ END LOOP label1;
+ SET @x = p1;
+END";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:186:"CREATE PROCEDURE doiterate(p1 INT)
+BEGIN
+ label1: LOOP
+ SET p1 = p1 + 1;
+ IF p1 < 10 THEN
+ ITERATE label1;
+ END IF;
+ LEAVE label1;
+ END LOOP label1;
+ SET @x = p1;
+END";s:3:"len";i:186;s:4:"last";i:186;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:73:{i:0;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"CREATE";s:5:"value";s:6:"CREATE";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:9:"PROCEDURE";s:5:"value";s:9:"PROCEDURE";s:4:"type";i:1;s:5:"flags";i:3;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:16;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:9:"doiterate";s:5:"value";s:9:"doiterate";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:17;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:26;}i:6;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:27;}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:29;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"INT";s:5:"value";s:3:"INT";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:30;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:33;}i:10;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:34;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"BEGIN";s:5:"value";s:5:"BEGIN";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:35;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:40;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:7:"label1:";s:5:"value";s:7:"label1:";s:4:"type";i:10;s:5:"flags";i:0;s:8:"position";i:43;}i:14;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:50;}i:15;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"LOOP";s:5:"value";s:4:"LOOP";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:51;}i:16;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:55;}i:17;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"SET";s:5:"value";s:3:"SET";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:60;}i:18;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:63;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:64;}i:20;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:66;}i:21;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:67;}i:22;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:68;}i:23;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:69;}i:24;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:71;}i:25;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:72;}i:26;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:73;}i:27;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:74;}i:28;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:75;}i:29;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:76;}i:30;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"IF";s:5:"value";s:2:"IF";s:4:"type";i:1;s:5:"flags";i:35;s:8:"position";i:81;}i:31;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:83;}i:32;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:84;}i:33;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:86;}i:34;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:87;}i:35;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:88;}i:36;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"10";s:5:"value";i:10;s:4:"type";i:6;s:5:"flags";i:0;s:8:"position";i:89;}i:37;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:91;}i:38;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"THEN";s:5:"value";s:4:"THEN";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:92;}i:39;O:15:"SqlParser\Token":5:{s:5:"token";s:7:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:96;}i:40;O:15:"SqlParser\Token":5:{s:5:"token";s:7:"ITERATE";s:5:"value";s:7:"ITERATE";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:103;}i:41;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:110;}i:42;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"label1";s:5:"value";s:6:"label1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:111;}i:43;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:117;}i:44;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:118;}i:45;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"END";s:5:"value";s:3:"END";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:123;}i:46;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:126;}i:47;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"IF";s:5:"value";s:2:"IF";s:4:"type";i:1;s:5:"flags";i:35;s:8:"position";i:127;}i:48;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:129;}i:49;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:130;}i:50;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"LEAVE";s:5:"value";s:5:"LEAVE";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:135;}i:51;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:140;}i:52;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"label1";s:5:"value";s:6:"label1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:141;}i:53;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:147;}i:54;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:148;}i:55;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"END";s:5:"value";s:3:"END";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:151;}i:56;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:154;}i:57;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"LOOP";s:5:"value";s:4:"LOOP";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:155;}i:58;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:159;}i:59;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"label1";s:5:"value";s:6:"label1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:160;}i:60;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:166;}i:61;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:167;}i:62;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"SET";s:5:"value";s:3:"SET";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:170;}i:63;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:173;}i:64;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"@x";s:5:"value";s:1:"x";s:4:"type";i:8;s:5:"flags";i:1;s:8:"position";i:174;}i:65;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:176;}i:66;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:177;}i:67;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:178;}i:68;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"p1";s:5:"value";s:2:"p1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:179;}i:69;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:181;}i:70;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:182;}i:71;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"END";s:5:"value";s:3:"END";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:183;}i:72;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:73;s:3:"idx";i:74;}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\CreateStatement":17:{s:4:"name";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:9:"doiterate";s:6:"column";N;s:4:"expr";s:9:"doiterate";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:13:"entityOptions";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:6:"fields";N;s:6:"select";N;s:4:"like";N;s:11:"partitionBy";N;s:13:"partitionsNum";N;s:14:"subpartitionBy";N;s:16:"subpartitionsNum";N;s:10:"partitions";N;s:5:"table";N;s:6:"return";N;s:10:"parameters";a:1:{i:0;O:40:"SqlParser\Components\ParameterDefinition":3:{s:4:"name";s:2:"p1";s:5:"inOut";N;s:4:"type";O:29:"SqlParser\Components\DataType":3:{s:4:"name";s:3:"INT";s:10:"parameters";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}}}}s:4:"body";a:62:{i:0;r:76;i:1;r:82;i:2;r:88;i:3;r:94;i:4;r:100;i:5;r:106;i:6;r:112;i:7;r:118;i:8;r:124;i:9;r:130;i:10;r:136;i:11;r:142;i:12;r:148;i:13;r:154;i:14;r:160;i:15;r:166;i:16;r:172;i:17;r:178;i:18;r:184;i:19;r:190;i:20;r:196;i:21;r:202;i:22;r:208;i:23;r:214;i:24;r:220;i:25;r:226;i:26;r:232;i:27;r:238;i:28;r:244;i:29;r:250;i:30;r:256;i:31;r:262;i:32;r:268;i:33;r:274;i:34;r:280;i:35;r:286;i:36;r:292;i:37;r:298;i:38;r:304;i:39;r:310;i:40;r:316;i:41;r:322;i:42;r:328;i:43;r:334;i:44;r:340;i:45;r:346;i:46;r:352;i:47;r:358;i:48;r:364;i:49;r:370;i:50;r:376;i:51;r:382;i:52;r:388;i:53;r:394;i:54;r:400;i:55;r:406;i:56;r:412;i:57;r:418;i:58;r:424;i:59;r:430;i:60;r:436;i:61;r:442;}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:1:{i:6;s:9:"PROCEDURE";}}s:5:"first";i:0;s:4:"last";i:73;}}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/parseSelect7.out b/tests/data/parser/parseSelect7.out
index f1a7dea..cd1ecb7 100644
--- a/tests/data/parser/parseSelect7.out
+++ b/tests/data/parser/parseSelect7.out
@@ -1,4 +1,4 @@
a:4:{s:5:"query";s:119:"SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:119:"SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
- ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)";s:3:"len";i:119;s:4:"last";i:119;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:58:{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:2:"t1";s:5:"value";s:2:"t1";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:16;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:9:"LEFT JOIN";s:5:"value";s:9:"LEFT JOIN";s:4:"type";i:1;s:5:"flags";i:7;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:26;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:27;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t2";s:5:"value";s:2:"t2";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:28;}i:12;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:13;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"CROSS";s:5:"value";s:5:"CROSS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:31;}i:14;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:36;}i:15;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"JOIN";s:5:"value";s:4:"JOIN";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:37;}i:16;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:41;}i:17;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t3";s:5:"value";s:2:"t3";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:42;}i:18;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:44;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"CROSS";s:5:"value";s:5:"CROSS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:45;}i:20;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:50;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"JOIN";s:5:"value";s:4:"JOIN";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:51;}i:22;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:55;}i:23;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t4";s:5:"value";s:2:"t4";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:56;}i:24;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:58;}i:25;O:15:"SqlParser\Token":5:{s:5:"token";s:18:"
- ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:59;}i:26;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"ON";s:5:"value";s:2:"ON";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:77;}i:27;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:79;}i:28;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:80;}i:29;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t2";s:5:"value";s:2:"t2";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:81;}i:30;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:83;}i:31;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"a";s:5:"value";s:1:"a";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:84;}i:32;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:85;}i:33;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t1";s:5:"value";s:2:"t1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:86;}i:34;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:88;}i:35;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"a";s:5:"value";s:1:"a";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:89;}i:36;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:90;}i:37;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:91;}i:38;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:94;}i:39;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t3";s:5:"value";s:2:"t3";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:95;}i:40;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:97;}i:41;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"b";s:5:"value";s:1:"b";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:98;}i:42;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:99;}i:43;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t1";s:5:"value";s:2:"t1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:100;}i:44;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:102;}i:45;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"b";s:5:"value";s:1:"b";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:103;}i:46;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:104;}i:47;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:105;}i:48;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:108;}i:49;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t4";s:5:"value";s:2:"t4";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:109;}i:50;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:111;}i:51;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"c";s:5:"value";s:1:"c";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:112;}i:52;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:113;}i:53;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t1";s:5:"value";s:2:"t1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:114;}i:54;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:116;}i:55;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"c";s:5:"value";s:1:"c";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:117;}i:56;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:118;}i:57;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:58;s:3:"idx";i:58;}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":15:{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:2:"t1";s:6:"column";N;s:4:"expr";s:2:"t1";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}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";a:1:{i:0;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:4:"LEFT";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:32:"(t2 CROSS JOIN t3 CROSS JOIN t4)";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:2:"on";a:5:{i:0;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:3:{i:0;s:2:"t2";i:1;s:1:"a";i:2;s:2:"t1";}s:10:"isOperator";b:0;s:4:"expr";s:10:"(t2.a=t1.a";}i:1;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:0:{}s:10:"isOperator";b:1;s:4:"expr";s:3:"AND";}i:2;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:3:{i:0;s:2:"t3";i:1;s:1:"b";i:2;s:2:"t1";}s:10:"isOperator";b:0;s:4:"expr";s:9:"t3.b=t1.b";}i:3;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:0:{}s:10:"isOperator";b:1;s:4:"expr";s:3:"AND";}i:4;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:3:{i:0;s:2:"t4";i:1;s:1:"c";i:2;s:2:"t1";}s:10:"isOperator";b:0;s:4:"expr";s:10:"t4.c=t1.c)";}}s:5:"using";N;}}s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:56;}}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
+ ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)";s:3:"len";i:119;s:4:"last";i:119;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:54:{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:2:"t1";s:5:"value";s:2:"t1";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:16;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:9:"LEFT JOIN";s:5:"value";s:9:"LEFT JOIN";s:4:"type";i:1;s:5:"flags";i:7;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:26;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:27;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t2";s:5:"value";s:2:"t2";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:28;}i:12;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:13;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"CROSS JOIN";s:5:"value";s:10:"CROSS JOIN";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:31;}i:14;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:41;}i:15;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t3";s:5:"value";s:2:"t3";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:42;}i:16;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:44;}i:17;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"CROSS JOIN";s:5:"value";s:10:"CROSS JOIN";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:45;}i:18;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:55;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t4";s:5:"value";s:2:"t4";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:56;}i:20;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:58;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:18:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:59;}i:22;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"ON";s:5:"value";s:2:"ON";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:77;}i:23;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:79;}i:24;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:80;}i:25;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t2";s:5:"value";s:2:"t2";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:81;}i:26;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:83;}i:27;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"a";s:5:"value";s:1:"a";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:84;}i:28;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:85;}i:29;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t1";s:5:"value";s:2:"t1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:86;}i:30;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:88;}i:31;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"a";s:5:"value";s:1:"a";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:89;}i:32;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:90;}i:33;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:91;}i:34;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:94;}i:35;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t3";s:5:"value";s:2:"t3";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:95;}i:36;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:97;}i:37;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"b";s:5:"value";s:1:"b";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:98;}i:38;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:99;}i:39;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t1";s:5:"value";s:2:"t1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:100;}i:40;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:102;}i:41;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"b";s:5:"value";s:1:"b";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:103;}i:42;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:104;}i:43;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:105;}i:44;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:108;}i:45;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t4";s:5:"value";s:2:"t4";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:109;}i:46;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:111;}i:47;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"c";s:5:"value";s:1:"c";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:112;}i:48;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:113;}i:49;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"t1";s:5:"value";s:2:"t1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:114;}i:50;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:116;}i:51;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"c";s:5:"value";s:1:"c";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:117;}i:52;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:118;}i:53;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:54;s:3:"idx";i:54;}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":15:{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:2:"t1";s:6:"column";N;s:4:"expr";s:2:"t1";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}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";a:1:{i:0;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:4:"LEFT";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:32:"(t2 CROSS JOIN t3 CROSS JOIN t4)";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:2:"on";a:5:{i:0;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:3:{i:0;s:2:"t2";i:1;s:1:"a";i:2;s:2:"t1";}s:10:"isOperator";b:0;s:4:"expr";s:10:"(t2.a=t1.a";}i:1;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:0:{}s:10:"isOperator";b:1;s:4:"expr";s:3:"AND";}i:2;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:3:{i:0;s:2:"t3";i:1;s:1:"b";i:2;s:2:"t1";}s:10:"isOperator";b:0;s:4:"expr";s:9:"t3.b=t1.b";}i:3;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:0:{}s:10:"isOperator";b:1;s:4:"expr";s:3:"AND";}i:4;O:30:"SqlParser\Components\Condition":3:{s:11:"identifiers";a:3:{i:0;s:2:"t4";i:1;s:1:"c";i:2;s:2:"t1";}s:10:"isOperator";b:0;s:4:"expr";s:10:"t4.c=t1.c)";}}s:5:"using";N;}}s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:52;}}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/parseSelectJoinCross.in b/tests/data/parser/parseSelectJoinCross.in
new file mode 100644
index 0000000..31b4feb
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinCross.in
@@ -0,0 +1,4 @@
+SELECT table112.id,table112.bval1,table112.bval2,
+table111.id,table111.aval1
+FROM table112
+CROSS JOIN table111 \ No newline at end of file
diff --git a/tests/data/parser/parseSelectJoinCross.out b/tests/data/parser/parseSelectJoinCross.out
new file mode 100644
index 0000000..dc4b623
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinCross.out
@@ -0,0 +1,10 @@
+a:4:{s:5:"query";s:110:"SELECT table112.id,table112.bval1,table112.bval2,
+table111.id,table111.aval1
+FROM table112
+CROSS JOIN table111";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:110:"SELECT table112.id,table112.bval1,table112.bval2,
+table111.id,table111.aval1
+FROM table112
+CROSS JOIN table111";s:3:"len";i:110;s:4:"last";i:110;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:31:{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:8:"table112";s:5:"value";s:8:"table112";s:4:"type";i:0;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:2;s:5:"flags";i:16;s:8:"position";i:15;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"id";s:5:"value";s:2:"id";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:16;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:18;}i:6;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"table112";s:5:"value";s:8:"table112";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:19;}i:7;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:27;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"bval1";s:5:"value";s:5:"bval1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:28;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:33;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"table112";s:5:"value";s:8:"table112";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:34;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:42;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"bval2";s:5:"value";s:5:"bval2";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:43;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:48;}i:14;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:49;}i:15;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"table111";s:5:"value";s:8:"table111";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:50;}i:16;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:58;}i:17;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"id";s:5:"value";s:2:"id";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:59;}i:18;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:61;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"table111";s:5:"value";s:8:"table111";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:62;}i:20;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:70;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"aval1";s:5:"value";s:5:"aval1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:71;}i:22;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:76;}i:23;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:77;}i:24;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:81;}i:25;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"table112";s:5:"value";s:8:"table112";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:82;}i:26;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:90;}i:27;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"CROSS JOIN";s:5:"value";s:10:"CROSS JOIN";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:91;}i:28;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:101;}i:29;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"table111";s:5:"value";s:8:"table111";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:102;}i:30;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:31;s:3:"idx";i:31;}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":15:{s:4:"expr";a:5:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:8:"table112";s:6:"column";s:2:"id";s:4:"expr";s:11:"table112.id";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}i:1;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:8:"table112";s:6:"column";s:5:"bval1";s:4:"expr";s:14:"table112.bval1";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}i:2;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:8:"table112";s:6:"column";s:5:"bval2";s:4:"expr";s:14:"table112.bval2";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}i:3;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:8:"table111";s:6:"column";s:2:"id";s:4:"expr";s:11:"table111.id";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}i:4;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:8:"table111";s:6:"column";s:5:"aval1";s:4:"expr";s:14:"table111.aval1";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:8:"table112";s:6:"column";N;s:4:"expr";s:8:"table112";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}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";a:1:{i:0;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:5:"CROSS";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:8:"table111";s:6:"column";N;s:4:"expr";s:8:"table111";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:2:"on";N;s:5:"using";N;}}s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:29;}}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/parseSelectJoinMultiple.in b/tests/data/parser/parseSelectJoinMultiple.in
new file mode 100644
index 0000000..39af387
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinMultiple.in
@@ -0,0 +1,2 @@
+SELECT * FROM Orders NATURAL JOIN Items_Orders NATURAL JOIN Items
+WHERE customer= 'username' \ No newline at end of file
diff --git a/tests/data/parser/parseSelectJoinMultiple.out b/tests/data/parser/parseSelectJoinMultiple.out
new file mode 100644
index 0000000..f796b3b
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinMultiple.out
@@ -0,0 +1,4 @@
+a:4:{s:5:"query";s:92:"SELECT * FROM Orders NATURAL JOIN Items_Orders NATURAL JOIN Items
+WHERE customer= 'username'";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:92:"SELECT * FROM Orders NATURAL JOIN Items_Orders NATURAL JOIN Items
+WHERE customer= 'username'";s:3:"len";i:92;s:4:"last";i:92;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:23:{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:"Orders";s:5:"value";s:6:"Orders";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:12:"NATURAL JOIN";s:5:"value";s:12:"NATURAL JOIN";s:4:"type";i:1;s:5:"flags";i:7;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:33;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:12:"Items_Orders";s:5:"value";s:12:"Items_Orders";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:34;}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:46;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:12:"NATURAL JOIN";s:5:"value";s:12:"NATURAL JOIN";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:47;}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:59;}i:14;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"Items";s:5:"value";s:5:"Items";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:60;}i:15;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:65;}i:16;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:66;}i:17;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:71;}i:18;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"customer";s:5:"value";s:8:"customer";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:72;}i:19;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:80;}i:20;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:81;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"'username'";s:5:"value";s:8:"username";s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:82;}i:22;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:23;s:3:"idx";i:23;}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":15:{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:"Orders";s:6:"column";N;s:4:"expr";s:6:"Orders";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:8:"customer";i:1;s:8:"username";}s:10:"isOperator";b:0;s:4:"expr";s:20:"customer= 'username'";}}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";a:2:{i:0;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:7:"NATURAL";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:12:"Items_Orders";s:6:"column";N;s:4:"expr";s:12:"Items_Orders";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:2:"on";N;s:5:"using";N;}i:1;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:7:"NATURAL";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:5:"Items";s:6:"column";N;s:4:"expr";s:5:"Items";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:2:"on";N;s:5:"using";N;}}s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:21;}}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/parseSelectJoinNatural.in b/tests/data/parser/parseSelectJoinNatural.in
new file mode 100644
index 0000000..606842d
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNatural.in
@@ -0,0 +1,3 @@
+SELECT id,aval1,cval1
+FROM table111
+NATURAL JOIN table113 \ No newline at end of file
diff --git a/tests/data/parser/parseSelectJoinNatural.out b/tests/data/parser/parseSelectJoinNatural.out
new file mode 100644
index 0000000..875b375
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNatural.out
@@ -0,0 +1,7 @@
+a:4:{s:5:"query";s:57:"SELECT id,aval1,cval1
+FROM table111
+NATURAL JOIN table113";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:57:"SELECT id,aval1,cval1
+FROM table111
+NATURAL JOIN table113";s:3:"len";i:57;s:4:"last";i:57;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:2:"id";s:5:"value";s:2:"id";s:4:"type";i:0;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:2;s:5:"flags";i:16;s:8:"position";i:9;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"aval1";s:5:"value";s:5:"aval1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:10;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:15;}i:6;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"cval1";s:5:"value";s:5:"cval1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:16;}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:21;}i:8;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:22;}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:8:"table111";s:5:"value";s:8:"table111";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:35;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:12:"NATURAL JOIN";s:5:"value";s:12:"NATURAL JOIN";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:36;}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:48;}i:14;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"table113";s:5:"value";s:8:"table113";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:49;}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":15:{s:4:"expr";a:3:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";s:2:"id";s:4:"expr";s:2:"id";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}i:1;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";s:5:"aval1";s:4:"expr";s:5:"aval1";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}i:2;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";s:5:"cval1";s:4:"expr";s:5:"cval1";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:8:"table111";s:6:"column";N;s:4:"expr";s:8:"table111";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}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";a:1:{i:0;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:7:"NATURAL";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:8:"table113";s:6:"column";N;s:4:"expr";s:8:"table113";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:2:"on";N;s:5:"using";N;}}s:5:"union";a:0:{}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:0:{}s:6:"parser";a:0:{}}} \ No newline at end of file
diff --git a/tests/data/parser/parseSelectJoinNaturalLeft.in b/tests/data/parser/parseSelectJoinNaturalLeft.in
new file mode 100644
index 0000000..bc99f6b
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNaturalLeft.in
@@ -0,0 +1,3 @@
+SELECT C.First_Name, C.Last_Name, O.title
+FROM Employee as C
+NATURAL LEFT JOIN JOb as O; \ No newline at end of file
diff --git a/tests/data/parser/parseSelectJoinNaturalLeft.out b/tests/data/parser/parseSelectJoinNaturalLeft.out
new file mode 100644
index 0000000..ef0e03e
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNaturalLeft.out
@@ -0,0 +1,7 @@
+a:4:{s:5:"query";s:88:"SELECT C.First_Name, C.Last_Name, O.title
+FROM Employee as C
+NATURAL LEFT JOIN JOb as O;";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:88:"SELECT C.First_Name, C.Last_Name, O.title
+FROM Employee as C
+NATURAL LEFT JOIN JOb as O;";s:3:"len";i:88;s:4:"last";i:88;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:33:{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:"C";s:5:"value";s:1:"C";s:4:"type";i:0;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:2;s:5:"flags";i:16;s:8:"position";i:8;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"First_Name";s:5:"value";s:10:"First_Name";s:4:"type";i:0;s:5:"flags";i:0;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:2;s:5:"flags";i:16;s:8:"position";i:19;}i:6;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:7;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"C";s:5:"value";s:1:"C";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:21;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:22;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:9:"Last_Name";s:5:"value";s:9:"Last_Name";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:23;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:32;}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:33;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"O";s:5:"value";s:1:"O";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:34;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:1:".";s:5:"value";s:1:".";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:35;}i:14;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"title";s:5:"value";s:5:"title";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:36;}i:15;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:41;}i:16;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:42;}i:17;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:46;}i:18;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"Employee";s:5:"value";s:8:"Employee";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:47;}i:19;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:55;}i:20;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"as";s:5:"value";s:2:"AS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:56;}i:21;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:58;}i:22;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"C";s:5:"value";s:1:"C";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:59;}i:23;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:60;}i:24;O:15:"SqlParser\Token":5:{s:5:"token";s:17:"NATURAL LEFT JOIN";s:5:"value";s:17:"NATURAL LEFT JOIN";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:61;}i:25;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:78;}i:26;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"JOb";s:5:"value";s:3:"JOb";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:79;}i:27;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:82;}i:28;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"as";s:5:"value";s:2:"AS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:83;}i:29;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:85;}i:30;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"O";s:5:"value";s:1:"O";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:86;}i:31;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:87;}i:32;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:33;s:3:"idx";i:33;}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":15:{s:4:"expr";a:3:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:1:"C";s:6:"column";s:10:"First_Name";s:4:"expr";s:12:"C.First_Name";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}i:1;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:1:"C";s:6:"column";s:9:"Last_Name";s:4:"expr";s:11:"C.Last_Name";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}i:2;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:1:"O";s:6:"column";s:5:"title";s:4:"expr";s:7:"O.title";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:8:"Employee";s:6:"column";N;s:4:"expr";s:8:"Employee";s:5:"alias";s:1:"C";s:8:"function";N;s:8:"subquery";N;}}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";a:1:{i:0;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:12:"NATURAL LEFT";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:3:"JOb";s:6:"column";N;s:4:"expr";s:3:"JOb";s:5:"alias";s:1:"O";s:8:"function";N;s:8:"subquery";N;}s:2:"on";N;s:5:"using";N;}}s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:30;}}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/parseSelectJoinNaturalLeftOuter.in b/tests/data/parser/parseSelectJoinNaturalLeftOuter.in
new file mode 100644
index 0000000..ab06720
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNaturalLeftOuter.in
@@ -0,0 +1 @@
+SELECT * FROM actor NATURAL LEFT OUTER JOIN film_actor; \ No newline at end of file
diff --git a/tests/data/parser/parseSelectJoinNaturalLeftOuter.out b/tests/data/parser/parseSelectJoinNaturalLeftOuter.out
new file mode 100644
index 0000000..1504d86
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNaturalLeftOuter.out
@@ -0,0 +1 @@
+a:4:{s:5:"query";s:55:"SELECT * FROM actor NATURAL LEFT OUTER JOIN film_actor;";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:55:"SELECT * FROM actor NATURAL LEFT OUTER JOIN film_actor;";s:3:"len";i:55;s:4:"last";i:55;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:13:{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:5:"actor";s:5:"value";s:5:"actor";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:19;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:23:"NATURAL LEFT OUTER JOIN";s:5:"value";s:23:"NATURAL LEFT OUTER JOIN";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:20;}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:43;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"film_actor";s:5:"value";s:10:"film_actor";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:44;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:54;}i:12;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:13;s:3:"idx";i:13;}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":15:{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:5:"actor";s:6:"column";N;s:4:"expr";s:5:"actor";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}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";a:1:{i:0;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:18:"NATURAL LEFT OUTER";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:10:"film_actor";s:6:"column";N;s:4:"expr";s:10:"film_actor";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:2:"on";N;s:5:"using";N;}}s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:10;}}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/parseSelectJoinNaturalRight.in b/tests/data/parser/parseSelectJoinNaturalRight.in
new file mode 100644
index 0000000..b5e2a9b
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNaturalRight.in
@@ -0,0 +1 @@
+SELECT * FROM actor NATURAL RIGHT JOIN film_actor;
diff --git a/tests/data/parser/parseSelectJoinNaturalRight.out b/tests/data/parser/parseSelectJoinNaturalRight.out
new file mode 100644
index 0000000..eae3c2a
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNaturalRight.out
@@ -0,0 +1,4 @@
+a:4:{s:5:"query";s:51:"SELECT * FROM actor NATURAL RIGHT JOIN film_actor;
+";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:51:"SELECT * FROM actor NATURAL RIGHT JOIN film_actor;
+";s:3:"len";i:51;s:4:"last";i:51;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:14:{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:5:"actor";s:5:"value";s:5:"actor";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:19;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:18:"NATURAL RIGHT JOIN";s:5:"value";s:18:"NATURAL RIGHT JOIN";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:20;}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:38;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"film_actor";s:5:"value";s:10:"film_actor";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:39;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:49;}i:12;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:50;}i:13;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:14;s:3:"idx";i:14;}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":15:{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:5:"actor";s:6:"column";N;s:4:"expr";s:5:"actor";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}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";a:1:{i:0;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:13:"NATURAL RIGHT";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:10:"film_actor";s:6:"column";N;s:4:"expr";s:10:"film_actor";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:2:"on";N;s:5:"using";N;}}s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:10;}}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/parseSelectJoinNaturalRightOuter.in b/tests/data/parser/parseSelectJoinNaturalRightOuter.in
new file mode 100644
index 0000000..0ef197f
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNaturalRightOuter.in
@@ -0,0 +1 @@
+SELECT * FROM actor NATURAL RIGHT OUTER JOIN film_actor; \ No newline at end of file
diff --git a/tests/data/parser/parseSelectJoinNaturalRightOuter.out b/tests/data/parser/parseSelectJoinNaturalRightOuter.out
new file mode 100644
index 0000000..7c47bca
--- /dev/null
+++ b/tests/data/parser/parseSelectJoinNaturalRightOuter.out
@@ -0,0 +1 @@
+a:4:{s:5:"query";s:56:"SELECT * FROM actor NATURAL RIGHT OUTER JOIN film_actor;";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:56:"SELECT * FROM actor NATURAL RIGHT OUTER JOIN film_actor;";s:3:"len";i:56;s:4:"last";i:56;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:13:{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:5:"actor";s:5:"value";s:5:"actor";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:19;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:24:"NATURAL RIGHT OUTER JOIN";s:5:"value";s:24:"NATURAL RIGHT OUTER JOIN";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:20;}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:44;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"film_actor";s:5:"value";s:10:"film_actor";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:45;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:55;}i:12;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:13;s:3:"idx";i:13;}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":15:{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:5:"actor";s:6:"column";N;s:4:"expr";s:5:"actor";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}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";a:1:{i:0;O:32:"SqlParser\Components\JoinKeyword":4:{s:4:"type";s:19:"NATURAL RIGHT OUTER";s:4:"expr";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:10:"film_actor";s:6:"column";N;s:4:"expr";s:10:"film_actor";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:2:"on";N;s:5:"using";N;}}s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:10;}}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/tools/contexts/_common.txt b/tools/contexts/_common.txt
index 509ee36..1a535a4 100644
--- a/tools/contexts/_common.txt
+++ b/tools/contexts/_common.txt
@@ -12,6 +12,7 @@ CHAR (D)
CHARACTER (D)
CHARACTER SET
CHARSET
+CROSS JOIN
DATA DIRECTORY
DATE (D)
DATETIME (D)
@@ -60,6 +61,11 @@ MULTILINESTRING (D)
MULTILINEPOINT (D)
MULTILINEPOLYGON (D)
MULTISET (D)
+NATURAL JOIN
+NATURAL LEFT JOIN
+NATURAL LEFT OUTER JOIN
+NATURAL RIGHT JOIN
+NATURAL RIGHT OUTER JOIN
NO ACTION
NO RELEASE
NOT NULL