Repository navigation
Conversation
isCaseExpressionAhead reads CASE followed by + or - as a column named case, so CASE -1 WHEN -1 THEN 'x' END failed to parse in a statement, and parseExpression returned only the subtraction case - 1 and dropped the rest. The LOOKAHEAD(3) it replaced in the Pratt rewrite took these as CASE expressions. After CASE + or CASE -, look for a WHEN of this CASE, outside of brackets and nested CASE expressions, before anything that ends the expression. A column named case followed by a sign, as in case - 1 or case - CASE WHEN a THEN 1 END, still parses as before.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A simple CASE whose switch value starts with
-or+no longer parses:SELECT CASE -1 WHEN -1 THEN 'x' END FROM tParseExceptionSELECT CASE -a WHEN 1 THEN 2 END FROM tParseExceptionCCJSqlParserUtil.parseExpression("CASE -a WHEN 1 THEN 2 END")case - a(aSubtractionon a column namedcase); the rest is droppedCASE ~1 WHEN …,CASE (-1) WHEN …andCASE 0 - 1 WHEN …parse. SQL allows any value expression as the CASE operand, and SQLite evaluates these statements.The cause is
isCaseExpressionAhead, added in the Pratt rewrite (365078d) in place ofLOOKAHEAD(3)onCaseWhenExpression(). It treatsCASEfollowed by+or-as a column namedcase, so thatSELECT case - 1 FROM tparses.With this change, when
+or-followsCASE, a new helperisWhenAheadOfCaseOperandwalks the token chain (nextWithItemToken, like the other lookahead helpers). It answers "CASE expression" if aWHENcomes before the expression ends, skipping brackets and nestedCASE … END. It answers "column" at),END,THEN,ELSE,FROM,WHERE,,,;or EOF at the same level. Socase - 1,case + 1,case - CASE WHEN a THEN 1 ENDandcase - (CASE a WHEN 1 THEN 2 END)still parse as a binary expression on a column namedcase. OnlyCASEfollowed by a sign goes through the walk, and it stops at the first token that ends the expression.Tests (
CaseExpressionTest):testSignedSwitchExpression: 7 expressions (-1,-a,+a,-a + b,-t.a,-abs(a),-(a)as the switch value). Each must round-trip and parse to aCaseExpressionwith that switch expression. All 7 fail on masterc84ad0eb(expected: <case-1 when-1 then 'negative' else 'other' end> but was: <case-1>, etc.).testCaseColumnFollowedBySign: the 4 column forms above, which must still give aBinaryExpression. They pass on master and with the change.What was run (Gradle with a JDK 17 toolchain):
./gradlew test --tests CaseExpressionTest: 28 tests, 7 failed without the grammar change, 0 failed with it../gradlew check: BUILD SUCCESSFUL. 12,273 tests, 0 failures, 25 skipped. Spotless, Checkstyle, PMD, SpotBugs and JaCoCo also pass.sqlite3). 20,000 randomSELECT <expr> FROM tstatements using arithmetic, bitwise, comparison,LIKE/GLOB,BETWEEN,IN,IS [NOT] NULL,CASE,CASTand a few functions were parsed and deparsed with JSqlParser. SQLite evaluated both the original and the deparsed SQL. On master, 0 results differ, and 43 statements that SQLite accepts fail to parse because of a signed CASE switch value. With this change, those 43 parse and their deparsed SQL gives the same result in SQLite. No statement that parsed on master fails now, and 0 results differ.Not run:
gradle jmh.