You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
parseStatements returns null instead of throwing JSQLParserException when withAllowComplexParsing(false) and the input does not parse #2576
CCJSqlParserUtil.parseStatements(sql, consumer) returns null instead of throwing JSQLParserException when complex parsing is switched off and the input does not parse. A caller that relies on the declared exception dereferences the result and fails with a NullPointerException of its own; a guard that treats "no exception" as "parsed" is misled.
Version:com.manticore-projects.jsqlformatter:jsqlparser:5.4.351-SNAPSHOT (build 5.4.351-20260910.100601-1), master at b2115ac8.
Reproduce
// default configuration: the documented exceptionCCJSqlParserUtil.parseStatements("PRAGMA foo");
// -> JSQLParserException: Encountered: <S_IDENTIFIER> / "PRAGMA", at line 1, column 1 ...// complex parsing off: null, no exceptionStatementss = CCJSqlParserUtil.parseStatements("PRAGMA foo", p -> p.withAllowComplexParsing(false));
// s == null// same for a broken script and for an empty statement between separatorsCCJSqlParserUtil.parseStatements("SELECT * FROM foo; PRAGMA x", p -> p.withAllowComplexParsing(false)); // nullCCJSqlParserUtil.parseStatements("SELECT * FROM foo;;", p -> p.withAllowComplexParsing(false)); // null// the single-statement entry point throws as expected with the same optionCCJSqlParserUtil.parse("PRAGMA foo", p -> p.withAllowComplexParsing(false));
// -> JSQLParserException
Also observed: parseStatements("/* nothing */") (default configuration) returns an empty Statements while parse("/* nothing */") throws JSQLParserException; the two entry points disagree on comment-only input.
Where
CCJSqlParserUtil.parseStatements(String, ExecutorService, Consumer) (CCJSqlParserUtil.java:471-501): the simple-parse attempt fails, the complex re-parse is skipped because allowComplexParsing is false, and the method falls through returning the unassigned result instead of rethrowing the first ParseException.
Suggestion
Rethrow the first parse failure as JSQLParserException when the complex re-parse is disabled (the way parse(String, ExecutorService, Consumer) does), and align the two entry points on comment-only input, either both empty or both throwing.
@manticore-projects The failure-propagation bug is fixed by #2568. Retested on master eddb1fb5: with withAllowComplexParsing(false), all three reported failing inputs (PRAGMA foo, SELECT * FROM foo; PRAGMA x, and SELECT * FROM foo;;) throw JSQLParserException. The existing ParseStatementsFailureTest tests pass as well.
The separate comment-only observation still holds: parse("/* nothing */") throws, while parseStatements("/* nothing */") returns an empty statement list. That API-consistency question is separate from the swallowed parse failures; #2568 preserved existing empty-input behavior.
Could you close the failure-propagation bug as fixed by #2568, and track the comment-only API policy separately if you want the two entry points aligned?
The separate comment-only observation still holds: parse("/* nothing /") throws, while parseStatements("/ nothing */") returns an empty statement list. That API-consistency question is separate from the swallowed parse failures; #2568 preserved existing empty-input behavior.
We had this discussion before: parseStatements("/* nothing */") clearly is an empty list, because it is not wrong -- just nothing to parse. While parse(...) clearly expects a statement and thus should not return null. (It could return null but really, then you had to check every statement for null, which does not make sense to me).
@stbischof will verify and close, he is a good friend of this project.
Thanks both — and thanks for the quick turnaround on the other three.
Verified on mastereddb1fb5 against the published snapshot 5.4.366-20260911.045237-1.
What works now
The failure propagation from #2568 is good. With withAllowComplexParsing(false):
input
before
now
PRAGMA foo
returned null
throws JSQLParserException
SELECT * FROM foo; PRAGMA x
returned null
throws JSQLParserException
SELECT * FROM foo;;
returned null
throws JSQLParserException
SELECT * FROM foo; DROP TABLE foo
2 statements
2 statements, unchanged
The other three reports are confirmed fixed as well, so those can stay closed: #2573 (SELECT DISTINCT a FROM t classifies instead of throwing), #2574 (a data-modifying CTE is reported as delete not allowed rather than throwing ClassCastException), #2575 (pg_sleep(1) OVER () reports [pg_sleep] and mayModifyData(), CONVERT(x USING y) reports [convert], and sum(id) OVER () with sum proven pure stays clean).
On the comment-only question
Agreed, and I withdraw that half of the report:
parseStatements("/* nothing */") clearly is an empty list, because it is not wrong -- just nothing to parse.
That is the right call.
What does not work yet
The second half of your own rule still has one case:
While parse(...) clearly expects a statement and thus should not return null.
The same guard sits on parse(String, ExecutorService, Consumer) (:103), newParser (:138) and parseAST (:154), and the same pattern on parseExpression (:186, :195), parseColumnDataType (:227), parseStatements' expression cousins (:261) and parseCondExpression (:313, :329).
Remaining task for this issue
Make parse("") and parse(null) throw JSQLParserException like every other input that yields no statement, so the method never returns null and agrees with parse(" "). parseStatements("") answering an empty list would be consistent with the comment-only behaviour you just confirmed.
Leaving this open for that; happy to close it once the empty-input case is aligned.
Activity
minleejae commentedon Sep 11, 2026
@manticore-projects The failure-propagation bug is fixed by #2568. Retested on master
eddb1fb5: withwithAllowComplexParsing(false), all three reported failing inputs (PRAGMA foo,SELECT * FROM foo; PRAGMA x, andSELECT * FROM foo;;) throwJSQLParserException. The existingParseStatementsFailureTesttests pass as well.The separate comment-only observation still holds:
parse("/* nothing */")throws, whileparseStatements("/* nothing */")returns an empty statement list. That API-consistency question is separate from the swallowed parse failures; #2568 preserved existing empty-input behavior.Could you close the failure-propagation bug as fixed by #2568, and track the comment-only API policy separately if you want the two entry points aligned?
manticore-projects commentedon Sep 11, 2026
Thank you much @minleejae!
We had this discussion before:
parseStatements("/* nothing */")clearly is an empty list, because it is not wrong -- just nothing to parse. Whileparse(...)clearly expects a statement and thus should not return null. (It could returnnullbut really, then you had to check every statement for null, which does not make sense to me).@stbischof will verify and close, he is a good friend of this project.
stbischof commentedon Sep 11, 2026
Thanks both — and thanks for the quick turnaround on the other three.
Verified on
mastereddb1fb5against the published snapshot5.4.366-20260911.045237-1.What works now
The failure propagation from #2568 is good. With
withAllowComplexParsing(false):PRAGMA foonullJSQLParserExceptionSELECT * FROM foo; PRAGMA xnullJSQLParserExceptionSELECT * FROM foo;;nullJSQLParserExceptionSELECT * FROM foo; DROP TABLE fooThe other three reports are confirmed fixed as well, so those can stay closed: #2573 (
SELECT DISTINCT a FROM tclassifies instead of throwing), #2574 (a data-modifying CTE is reported asdelete not allowedrather than throwingClassCastException), #2575 (pg_sleep(1) OVER ()reports[pg_sleep]andmayModifyData(),CONVERT(x USING y)reports[convert], andsum(id) OVER ()withsumproven pure stays clean).On the comment-only question
Agreed, and I withdraw that half of the report:
That is the right call.
What does not work yet
The second half of your own rule still has one case:
An empty string is short-circuited before the parser ever runs, a blank string is not, so the two disagree:
The same guard sits on
parse(String, ExecutorService, Consumer)(:103),newParser(:138) andparseAST(:154), and the same pattern onparseExpression(:186, :195),parseColumnDataType(:227),parseStatements' expression cousins (:261) andparseCondExpression(:313, :329).Remaining task for this issue
Make
parse("")andparse(null)throwJSQLParserExceptionlike every other input that yields no statement, so the method never returnsnulland agrees withparse(" ").parseStatements("")answering an empty list would be consistent with the comment-only behaviour you just confirmed.Leaving this open for that; happy to close it once the empty-input case is aligned.
fix(parser): align empty statement input handling (JSQLParser#2594)