Repository navigation
fix: parse truth tests after predicates - #2762
JimmyLiuJia wants to merge 1 commit into
Conversation
|
|
|
For that particular WHERE example,
SELECT NULL IN (1, 2) IS FALSE, NULL NOT IN (1, 2);
-- 0, NULLSo the difference matters when returning the boolean value, even though it does not change which rows the reported WHERE clause selects. SQLite documents this in Boolean expressions and the IN/NOT IN result matrix. The parser change keeps the existing truth-test AST types and accepts the three forms in #2759. |
|
For the original example, For the broader truth-test family, -- SQLite 3.53, t(a) = {1, 0, NULL}
SELECT count(*) FROM t WHERE a > 0 IS NOT TRUE; -- 2
SELECT count(*) FROM t WHERE NOT a > 0; -- 1That behavior is covered by SQLite's boolean expressions and IS/IS NOT semantics. There is also a related parser limitation worth tracking: -- master PR head
SELECT * FROM t WHERE a IS TRUE; ok ok
SELECT * FROM t WHERE (a > 0) IS TRUE; ok ok
SELECT * FROM t WHERE a > 0 IS TRUE; fail pass
SELECT * FROM t WHERE a > 0 IS NOT NULL; fail fail
SELECT * FROM t WHERE a = 1 IS NULL; fail fail
SELECT * FROM t WHERE a IS NOT NULL IS NULL; fail fail
SELECT * FROM t WHERE a > 0 IS DISTINCT FROM b; fail fail
The shared cause is the single condition-suffix slot in These are relevant dialect forms. PostgreSQL places IS tests below comparison operators, and MySQL's expression grammar allows The PR improves the cases shown, with no regression in this comparison. I would prefer to cover the related null and distinctness families together. If that would broaden this PR too much, the remaining cases should be tracked explicitly as follow-up work. |
|
|
Fixes #2759.
Statements such as
a > 0 IS TRUE,a IN (1, 2) IS FALSE, anda IS NULL IS NOT TRUEcurrently fail at the finalIS: the condition suffix dispatch treats truth tests as alternatives to the comparison or other predicate. Consume the optionalIS [NOT] TRUE/FALSE/UNKNOWNafter the complete predicate, reusing the existing expression types and preserving the precedence of leadingNOTand outerAND/OR. A sharedIS [NOT]prefix avoids separate Boolean and UNKNOWN lookahead probes. Bare and parenthesized truth tests continue to use the same AST types.Add 25 regression/compatibility cases covering parse/deparse, AST structure, comparisons, IN, IS NULL, BETWEEN, LIKE, EXISTS, UNKNOWN, negation, logical precedence, select items, malformed suffixes, and the existing partial-expression parsing behavior. Thirteen regression cases fail on the unmodified base commit; all 25 cases pass with the fix.
Validation on Windows with JDK 17.0.20.1 and Gradle 9.8.0:
checkpassed, including grammar ambiguity, Checkstyle, PMD, SpotBugs, formatting, and coverage checks. JUnit XML reports 9,765 passed, 25 skipped, and no failures. Tests used a writable local temporary directory throughjava.io.tmpdir.JSQLParserBenchmark.parseSQLStatements,version=latest, SIMPLE configuration, identical dependency classes and corpus, with a fixed 1 GiB heap and the GC profiler: 3 forks, 2 warmup iterations of 10 seconds, and 5 measurement iterations of 1 second per fork. Runs used baseline/fixed/fixed/baseline order.The first fixed run includes an unexplained slower fork (maximum measurement 208.510 ms/op); the repeated fixed run is comparable to the baseline runs. Keeping all measurements, the combined mean is 9.1% higher and the median is 1.9% lower. Allocation is approximately 7.356 million B/op in all four runs. These measurements cover the project's
performance.sqlcorpus and cannot rule out smaller performance changes or changes in tail latency.