diff --git a/src/Contexts/ContextMySql50000.php b/src/Contexts/ContextMySql50000.php index f8afd18f3..82ec3bd1f 100644 --- a/src/Contexts/ContextMySql50000.php +++ b/src/Contexts/ContextMySql50000.php @@ -145,8 +145,8 @@ 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, - 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, - 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, + 'CROSS JOIN' => 7, 'FOR UPDATE' => 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, 'NATURAL JOIN' => 7, 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7, @@ -156,7 +156,7 @@ class ContextMySql50000 extends Context 'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7, 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7, - 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, + 'LOCK IN SHARE MODE' => 7, 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, 'DEFAULT CHARACTER SET' => 7, 'NATURAL LEFT OUTER JOIN' => 7, 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7, diff --git a/src/Contexts/ContextMySql50100.php b/src/Contexts/ContextMySql50100.php index dd2b6774c..f63d17458 100644 --- a/src/Contexts/ContextMySql50100.php +++ b/src/Contexts/ContextMySql50100.php @@ -159,8 +159,8 @@ 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, - 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, - 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, + 'CROSS JOIN' => 7, 'FOR UPDATE' => 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, 'NATURAL JOIN' => 7, 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7, @@ -170,7 +170,7 @@ class ContextMySql50100 extends Context 'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7, 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7, - 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, + 'LOCK IN SHARE MODE' => 7, 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, 'DEFAULT CHARACTER SET' => 7, 'NATURAL LEFT OUTER JOIN' => 7, 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7, diff --git a/src/Contexts/ContextMySql50500.php b/src/Contexts/ContextMySql50500.php index 02acdacf0..a015dd82f 100644 --- a/src/Contexts/ContextMySql50500.php +++ b/src/Contexts/ContextMySql50500.php @@ -163,8 +163,8 @@ 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, - 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, - 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, + 'CROSS JOIN' => 7, 'FOR UPDATE' => 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, 'NATURAL JOIN' => 7, 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7, @@ -174,7 +174,7 @@ class ContextMySql50500 extends Context 'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7, 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7, - 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, + 'LOCK IN SHARE MODE' => 7, 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, 'DEFAULT CHARACTER SET' => 7, 'NATURAL LEFT OUTER JOIN' => 7, 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7, diff --git a/src/Contexts/ContextMySql50600.php b/src/Contexts/ContextMySql50600.php index 11439780a..94655aefb 100644 --- a/src/Contexts/ContextMySql50600.php +++ b/src/Contexts/ContextMySql50600.php @@ -169,8 +169,8 @@ 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, - 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, - 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, + 'CROSS JOIN' => 7, 'FOR UPDATE' => 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, 'NATURAL JOIN' => 7, 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7, @@ -180,7 +180,7 @@ class ContextMySql50600 extends Context 'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7, 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7, - 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, + 'LOCK IN SHARE MODE' => 7, 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, 'DEFAULT CHARACTER SET' => 7, 'NATURAL LEFT OUTER JOIN' => 7, 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7, diff --git a/src/Contexts/ContextMySql50700.php b/src/Contexts/ContextMySql50700.php index 04f410b59..9f83e0f50 100644 --- a/src/Contexts/ContextMySql50700.php +++ b/src/Contexts/ContextMySql50700.php @@ -175,8 +175,8 @@ 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, - 'CROSS JOIN' => 7, 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, - 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, + 'CROSS JOIN' => 7, 'FOR UPDATE' => 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, 'NATURAL JOIN' => 7, 'PARTITION BY' => 7, 'SET PASSWORD' => 7, 'SQL SECURITY' => 7, @@ -186,7 +186,7 @@ class ContextMySql50700 extends Context 'INDEX DIRECTORY' => 7, 'LEFT OUTER JOIN' => 7, 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'RIGHT OUTER JOIN' => 7, 'NATURAL LEFT JOIN' => 7, 'START TRANSACTION' => 7, - 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, + 'LOCK IN SHARE MODE' => 7, 'NATURAL RIGHT JOIN' => 7, 'SELECT TRANSACTION' => 7, 'DEFAULT CHARACTER SET' => 7, 'NATURAL LEFT OUTER JOIN' => 7, 'NATURAL RIGHT OUTER JOIN' => 7, 'WITH CONSISTENT SNAPSHOT' => 7, diff --git a/src/Parser.php b/src/Parser.php index d98e8dc27..ddefc7ee7 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -111,6 +111,12 @@ class Parser 'class' => 'SqlParser\\Components\\OptionsArray', 'field' => 'options', ), + '_END_OPTIONS' => array( + 'class' => 'SqlParser\\Components\\OptionsArray', + 'field' => 'end_options', + ), + + 'UNION' => array( 'class' => 'SqlParser\\Components\\UnionKeyword', 'field' => 'union', diff --git a/src/Statement.php b/src/Statement.php index b4769efb0..fd169df82 100644 --- a/src/Statement.php +++ b/src/Statement.php @@ -352,10 +352,23 @@ public function parse(Parser $parser, TokensList $list) $parsedOptions = true; } } elseif ($class === null) { - // There is no parser for this keyword and isn't the beginning - // of a statement (so no options) either. - $parser->error(__('Unrecognized keyword.'), $token); - continue; + // Handle special end options in Select statement + // See Statements\SelectStatement::$END_OPTIONS + if (get_class($this) === 'SqlParser\Statements\SelectStatement' + && ($token->value === 'FOR UPDATE' + || $token->value === 'LOCK IN SHARE MODE') + ) { + $this->end_options = OptionsArray::parse( + $parser, + $list, + static::$END_OPTIONS + ); + } else { + // There is no parser for this keyword and isn't the beginning + // of a statement (so no options) either. + $parser->error(__('Unrecognized keyword.'), $token); + continue; + } } $this->before($parser, $list, $token); diff --git a/src/Statements/SelectStatement.php b/src/Statements/SelectStatement.php index 8ff0b454c..624a0c5f2 100644 --- a/src/Statements/SelectStatement.php +++ b/src/Statements/SelectStatement.php @@ -74,6 +74,11 @@ class SelectStatement extends Statement 'SQL_CALC_FOUND_ROWS' => 9, ); + public static $END_OPTIONS = array( + 'FOR UPDATE' => 1, + 'LOCK IN SHARE MODE' => 1 + ); + /** * The clauses of this statement, in order. * @@ -111,6 +116,7 @@ class SelectStatement extends Statement 'LIMIT' => array('LIMIT', 3), 'PROCEDURE' => array('PROCEDURE', 3), 'UNION' => array('UNION', 1), + '_END_OPTIONS' => array('_END_OPTIONS', 1) // These are available only when `UNION` is present. // 'ORDER BY' => array('ORDER BY', 3), // 'LIMIT' => array('LIMIT', 3), @@ -200,6 +206,15 @@ class SelectStatement extends Statement */ public $union = array(); + /** + * The end options of this query. + * + * @var OptionsArray + * + * @see static::$END_OPTIONS + */ + public $end_options; + /** * Gets the clauses of this statement. * diff --git a/tests/Builder/SelectStatementTest.php b/tests/Builder/SelectStatementTest.php index 6f098886f..a2dd5af11 100644 --- a/tests/Builder/SelectStatementTest.php +++ b/tests/Builder/SelectStatementTest.php @@ -53,4 +53,27 @@ public function testBuilderAlias() $stmt->build() ); } + + public function testBuilderEndOptions() + { + /* Assertion 1 */ + $query = 'SELECT pid, name2 FROM tablename WHERE pid = 20 FOR UPDATE '; + $parser = new Parser($query); + $stmt = $parser->statements[0]; + + $this->assertEquals( + $query, + $stmt->build() + ); + + /* Assertion 2 */ + $query = 'SELECT pid, name2 FROM tablename WHERE pid = 20 LOCK IN SHARE MODE '; + $parser = new Parser($query); + $stmt = $parser->statements[0]; + + $this->assertEquals( + $query, + $stmt->build() + ); + } } diff --git a/tests/Parser/SelectStatementTest.php b/tests/Parser/SelectStatementTest.php index d3a4c9ed9..025c6d7e7 100644 --- a/tests/Parser/SelectStatementTest.php +++ b/tests/Parser/SelectStatementTest.php @@ -56,6 +56,9 @@ public function testSelectProvider() array('parser/parseSelectJoinNaturalRightOuter'), array('parser/parseSelectJoinMultiple'), array('parser/parseSelectWrongOrder'), + array('parser/parseSelectEndOptions1'), + array('parser/parseSelectEndOptions2'), + array('parser/parseSelectEndOptionsErr'), ); } } diff --git a/tests/data/parser/parseSelectEndOptions1.in b/tests/data/parser/parseSelectEndOptions1.in new file mode 100644 index 000000000..cc11abb06 --- /dev/null +++ b/tests/data/parser/parseSelectEndOptions1.in @@ -0,0 +1 @@ +SELECT pid, name2 FROM tablename WHERE pid = 20 /* FOR UPDATE end_option */ FOR UPDATE \ No newline at end of file diff --git a/tests/data/parser/parseSelectEndOptions1.out b/tests/data/parser/parseSelectEndOptions1.out new file mode 100644 index 000000000..141b928c3 --- /dev/null +++ b/tests/data/parser/parseSelectEndOptions1.out @@ -0,0 +1 @@ +a:4:{s:5:"query";s:86:"SELECT pid, name2 FROM tablename WHERE pid = 20 /* FOR UPDATE end_option */ FOR UPDATE";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:86:"SELECT pid, name2 FROM tablename WHERE pid = 20 /* FOR UPDATE end_option */ FOR UPDATE";s:3:"len";i:86;s:4:"last";i:86;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:3:"pid";s:5:"value";s:3:"pid";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:10;}i:4;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:11;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"name2";s:5:"value";s:5:"name2";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:12;}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:17;}i:7;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:18;}i:8;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:22;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:9:"tablename";s:5:"value";s:9:"tablename";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:3;s:5:"flags";i:0;s:8:"position";i:32;}i:11;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:33;}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:38;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"pid";s:5:"value";s:3:"pid";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:39;}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:42;}i:15;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:43;}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:2:"20";s:5:"value";i:20;s:4:"type";i:6;s:5:"flags";i:0;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:47;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:27:"/* FOR UPDATE end_option */";s:5:"value";s:27:"/* FOR UPDATE end_option */";s:4:"type";i:4;s:5:"flags";i:2;s:8:"position";i:48;}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:75;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"FOR UPDATE";s:5:"value";s:10:"FOR UPDATE";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:76;}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":16:{s:4:"expr";a:2:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";s:3:"pid";s:4:"expr";s:3:"pid";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:"name2";s:4:"expr";s:5:"name2";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:9:"tablename";s:6:"column";N;s:4:"expr";s:9:"tablename";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:1:{i:0;s:3:"pid";}s:10:"isOperator";b:0;s:4:"expr";s:8:"pid = 20";}}s:5:"group";N;s:6:"having";N;s:5:"order";N;s:5:"limit";N;s:9:"procedure";N;s:4:"into";N;s:4:"join";N;s:5:"union";a:0:{}s:11:"end_options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:1:{i:1;s:10:"FOR UPDATE";}}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/parseSelectEndOptions2.in b/tests/data/parser/parseSelectEndOptions2.in new file mode 100644 index 000000000..2e44c63c2 --- /dev/null +++ b/tests/data/parser/parseSelectEndOptions2.in @@ -0,0 +1,2 @@ +SELECT pid, name2 FROM tablename WHERE pid = 20 +/* LOCK IN SHARE MODE end_option */ LOCK IN SHARE MODE \ No newline at end of file diff --git a/tests/data/parser/parseSelectEndOptions2.out b/tests/data/parser/parseSelectEndOptions2.out new file mode 100644 index 000000000..4691c5994 --- /dev/null +++ b/tests/data/parser/parseSelectEndOptions2.out @@ -0,0 +1,4 @@ +a:4:{s:5:"query";s:102:"SELECT pid, name2 FROM tablename WHERE pid = 20 +/* LOCK IN SHARE MODE end_option */ LOCK IN SHARE MODE";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:102:"SELECT pid, name2 FROM tablename WHERE pid = 20 +/* LOCK IN SHARE MODE end_option */ LOCK IN SHARE MODE";s:3:"len";i:102;s:4:"last";i:102;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:3:"pid";s:5:"value";s:3:"pid";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:10;}i:4;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:11;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"name2";s:5:"value";s:5:"name2";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:12;}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:17;}i:7;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:18;}i:8;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:22;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:9:"tablename";s:5:"value";s:9:"tablename";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:3;s:5:"flags";i:0;s:8:"position";i:32;}i:11;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:33;}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:38;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"pid";s:5:"value";s:3:"pid";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:39;}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:42;}i:15;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:43;}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:2:"20";s:5:"value";i:20;s:4:"type";i:6;s:5:"flags";i:0;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:47;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:35:"/* LOCK IN SHARE MODE end_option */";s:5:"value";s:35:"/* LOCK IN SHARE MODE end_option */";s:4:"type";i:4;s:5:"flags";i:2;s:8:"position";i:48;}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:83;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:18:"LOCK IN SHARE MODE";s:5:"value";s:18:"LOCK IN SHARE MODE";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:84;}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":16:{s:4:"expr";a:2:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";s:3:"pid";s:4:"expr";s:3:"pid";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:"name2";s:4:"expr";s:5:"name2";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:9:"tablename";s:6:"column";N;s:4:"expr";s:9:"tablename";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:1:{i:0;s:3:"pid";}s:10:"isOperator";b:0;s:4:"expr";s:8:"pid = 20";}}s:5:"group";N;s:6:"having";N;s:5:"order";N;s:5:"limit";N;s:9:"procedure";N;s:4:"into";N;s:4:"join";N;s:5:"union";a:0:{}s:11:"end_options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:1:{i:1;s:18:"LOCK IN SHARE MODE";}}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/parseSelectEndOptionsErr.in b/tests/data/parser/parseSelectEndOptionsErr.in new file mode 100644 index 000000000..d6c6071e8 --- /dev/null +++ b/tests/data/parser/parseSelectEndOptionsErr.in @@ -0,0 +1,3 @@ +SELECT pid, name2 FROM tablename WHERE pid = 20 +/* USE both end_option, gives error */ +FOR UPDATE LOCK IN SHARE MODE \ No newline at end of file diff --git a/tests/data/parser/parseSelectEndOptionsErr.out b/tests/data/parser/parseSelectEndOptionsErr.out new file mode 100644 index 000000000..b7c1d0bbb --- /dev/null +++ b/tests/data/parser/parseSelectEndOptionsErr.out @@ -0,0 +1,7 @@ +a:4:{s:5:"query";s:116:"SELECT pid, name2 FROM tablename WHERE pid = 20 +/* USE both end_option, gives error */ +FOR UPDATE LOCK IN SHARE MODE";s:5:"lexer";O:15:"SqlParser\Lexer":8:{s:6:"strict";b:0;s:3:"str";s:116:"SELECT pid, name2 FROM tablename WHERE pid = 20 +/* USE both end_option, gives error */ +FOR UPDATE LOCK IN SHARE MODE";s:3:"len";i:116;s:4:"last";i:116;s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:25:{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:3:"pid";s:5:"value";s:3:"pid";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:10;}i:4;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:11;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"name2";s:5:"value";s:5:"name2";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:12;}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:17;}i:7;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:18;}i:8;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:22;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:9:"tablename";s:5:"value";s:9:"tablename";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:3;s:5:"flags";i:0;s:8:"position";i:32;}i:11;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:33;}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:38;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"pid";s:5:"value";s:3:"pid";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:39;}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:42;}i:15;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:43;}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:2:"20";s:5:"value";i:20;s:4:"type";i:6;s:5:"flags";i:0;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:47;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:38:"/* USE both end_option, gives error */";s:5:"value";s:38:"/* USE both end_option, gives error */";s:4:"type";i:4;s:5:"flags";i:2;s:8:"position";i:48;}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:86;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"FOR UPDATE";s:5:"value";s:10:"FOR UPDATE";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:87;}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:97;}i:23;O:15:"SqlParser\Token":5:{s:5:"token";s:18:"LOCK IN SHARE MODE";s:5:"value";s:18:"LOCK IN SHARE MODE";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:98;}i:24;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:25;s:3:"idx";i:25;}s:9:"delimiter";s:1:";";s:12:"delimiterLen";i:1;s:6:"errors";a:0:{}}s:6:"parser";O:16:"SqlParser\Parser":5:{s:4:"list";r:8;s:6:"strict";b:0;s:6:"errors";a:0:{}s:10:"statements";a:1:{i:0;O:36:"SqlParser\Statements\SelectStatement":16:{s:4:"expr";a:2:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";s:3:"pid";s:4:"expr";s:3:"pid";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:"name2";s:4:"expr";s:5:"name2";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:9:"tablename";s:6:"column";N;s:4:"expr";s:9:"tablename";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:1:{i:0;s:3:"pid";}s:10:"isOperator";b:0;s:4:"expr";s:8:"pid = 20";}}s:5:"group";N;s:6:"having";N;s:5:"order";N;s:5:"limit";N;s:9:"procedure";N;s:4:"into";N;s:4:"join";N;s:5:"union";a:0:{}s:11:"end_options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:2:{i:1;s:10:"FOR UPDATE";i:3;s:18:"LOCK IN SHARE MODE";}}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:23;}}s:8:"brackets";i:0;}s:6:"errors";a:2:{s:5:"lexer";a:0:{}s:6:"parser";a:1:{i:0;a:3:{i:0;s:40:"This option conflicts with "FOR UPDATE".";i:1;r:148;i:2;i:0;}}}} \ No newline at end of file diff --git a/tools/contexts/_common.txt b/tools/contexts/_common.txt index 1a535a4f4..5e58dbb74 100644 --- a/tools/contexts/_common.txt +++ b/tools/contexts/_common.txt @@ -24,6 +24,7 @@ DOUBLE (D) ENUM (D) FLOAT (D) FOR EACH ROW +FOR UPDATE FOREIGN KEY (K) FULL JOIN FULL OUTER JOIN @@ -45,6 +46,7 @@ INTEGER (D) INTERVAL (D) JSON (D) KEY (K) +LOCK IN SHARE MODE LEFT JOIN LEFT OUTER JOIN LESS THAN