CCJSqlParserUtil.parse(sql) returns the first statement and drops whatever follows a
semicolon without any error, so parse("SELECT a FROM t; DROP TABLE t") is a plain Select.
A caller that uses parse() as "the one statement I was given" - a read-only guard, a query
rewriter, a dispatcher - validates or rewrites only the SELECT and never sees the DROP.
Version: com.manticore-projects.jsqlformatter:jsqlparser:5.4.15 (release), grammar
unchanged on master at 60c8dc29. Same on 5.3.167.
Reproduce
CCJSqlParserUtil.parse("SELECT foo.id FROM foo; DROP TABLE foo");
// -> PlainSelect "SELECT foo.id FROM foo", no exception
CCJSqlParserUtil.parse("SELECT foo.id FROM foo; garbage here");
// -> PlainSelect, no exception
CCJSqlParserUtil.parse("SELECT foo.id FROM foo;;");
// -> PlainSelect, no exception
| input |
parse |
parse(withAllowComplexParsing(false)) |
parseStatements |
SELECT foo.id FROM foo; DROP TABLE foo |
Select, DROP dropped |
same |
2 statements |
SELECT foo.id FROM foo;DROP TABLE foo |
Select, DROP dropped |
same |
2 statements |
SELECT foo.id FROM foo; DROP TABLE foo; |
Select, DROP dropped |
same |
2 statements |
SELECT foo.id FROM foo; garbage here |
Select, rest dropped |
same |
JSQLParserException |
SELECT foo.id FROM foo;; |
Select, rest dropped |
same |
JSQLParserException |
So parseStatements is strict about the remainder while parse is not, and parse is not
even consistent with itself: SELECT foo.id FROM foo DROP TABLE foo (no semicolon) is
rejected, the same input with a semicolon is accepted and truncated.
Cause
The entry rule Statement() in JSqlParserCC.jjt ends a statement with
( <ST_SEMICOLON> | <EOF> ): after a semicolon nothing requires <EOF>, so the parser returns
as soon as the first statement is complete. CCJSqlParserUtil.parseStatement(parser, ..)
calls parser::Statement and returns its result without looking at the next token, unlike
parseExpression / parseCondExpression, which do check
parser.getNextToken().kind != CCJSqlParserTokenManager.EOF and fail on trailing input.
Suggestion
Make the single-statement entry points require that the input is consumed:
- in
Statement(), [ <ST_SEMICOLON> ] <EOF> after SingleStatement() | Block() (the rule is
only used for single statements; Statements() has its own loop), or
- in
CCJSqlParserUtil.parseStatement(..), the same EOF check that parseExpression does,
throwing JSQLParserException for trailing input.
Either way parse("SELECT ..; DROP TABLE ..") should throw, and callers who want a script keep
using parseStatements. This is the counterpart of #2576 (which fixed parseStatements
swallowing failures): a single-statement API should not swallow statements.
CCJSqlParserUtil.parse(sql)returns the first statement and drops whatever follows asemicolon without any error, so
parse("SELECT a FROM t; DROP TABLE t")is a plainSelect.A caller that uses
parse()as "the one statement I was given" - a read-only guard, a queryrewriter, a dispatcher - validates or rewrites only the
SELECTand never sees theDROP.Version:
com.manticore-projects.jsqlformatter:jsqlparser:5.4.15(release), grammarunchanged on
masterat60c8dc29. Same on 5.3.167.Reproduce
parseparse(withAllowComplexParsing(false))parseStatementsSELECT foo.id FROM foo; DROP TABLE fooSelect, DROP droppedSELECT foo.id FROM foo;DROP TABLE fooSelect, DROP droppedSELECT foo.id FROM foo; DROP TABLE foo;Select, DROP droppedSELECT foo.id FROM foo; garbage hereSelect, rest droppedJSQLParserExceptionSELECT foo.id FROM foo;;Select, rest droppedJSQLParserExceptionSo
parseStatementsis strict about the remainder whileparseis not, andparseis noteven consistent with itself:
SELECT foo.id FROM foo DROP TABLE foo(no semicolon) isrejected, the same input with a semicolon is accepted and truncated.
Cause
The entry rule
Statement()inJSqlParserCC.jjtends a statement with( <ST_SEMICOLON> | <EOF> ): after a semicolon nothing requires<EOF>, so the parser returnsas soon as the first statement is complete.
CCJSqlParserUtil.parseStatement(parser, ..)calls
parser::Statementand returns its result without looking at the next token, unlikeparseExpression/parseCondExpression, which do checkparser.getNextToken().kind != CCJSqlParserTokenManager.EOFand fail on trailing input.Suggestion
Make the single-statement entry points require that the input is consumed:
Statement(),[ <ST_SEMICOLON> ] <EOF>afterSingleStatement() | Block()(the rule isonly used for single statements;
Statements()has its own loop), orCCJSqlParserUtil.parseStatement(..), the sameEOFcheck thatparseExpressiondoes,throwing
JSQLParserExceptionfor trailing input.Either way
parse("SELECT ..; DROP TABLE ..")should throw, and callers who want a script keepusing
parseStatements. This is the counterpart of #2576 (which fixedparseStatementsswallowing failures): a single-statement API should not swallow statements.