Skip to content

Commit 21ac7c4

Browse files
committed
fix: treat a positional parameter '?' as a valid end of the ternary then-branch
A bare '?' (anonymous token, no kind constant) was missing from canEndExpression(), so a ternary whose then-branch ends with a positional parameter was silently misread as a jsonb operator: SELECT a ? ? : c FROM t parsed as JsonOperator(a, JsonExpression(?:c)) instead of TernaryExpression(a, JdbcParameter, c). Recognize it by image, like the closing brackets, and pin the AST shape with a regression test. Follow-up to #2476. Signed-off-by: 付典 <fudianchn@gmail.com>
1 parent 5080d19 commit 21ac7c4

2 files changed

Lines changed: 25 additions & 2 deletions

File tree

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,9 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
280280
* in operand position instead (directly after an operator, e.g. `x = :name`
281281
* or directly after the leading "?") starts a JDBC named parameter.
282282
* DATA_TYPE tokens end expressions as well, because a cast's target type
283-
* (`b :: int`) or a bare type keyword closes the then-branch.
283+
* (`b :: int`) or a bare type keyword closes the then-branch. The bare "?"
284+
* positional parameter has no token-kind constant (anonymous token), so it
285+
* is recognized by its image, like the closing brackets.
284286
*/
285287
private boolean canEndExpression(Token t) {
286288
if (t == null) {
@@ -294,7 +296,8 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
294296
return true;
295297
default:
296298
return (t.kind >= MIN_NON_RESERVED_WORD && t.kind <= MAX_NON_RESERVED_WORD)
297-
|| ")".equals(t.image) || "]".equals(t.image);
299+
|| ")".equals(t.image) || "]".equals(t.image)
300+
|| "?".equals(t.image);
298301
}
299302
}
300303

src/test/java/net/sf/jsqlparser/expression/TernaryExpressionTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package net.sf.jsqlparser.expression;
1111

1212
import net.sf.jsqlparser.JSQLParserException;
13+
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
1314
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
1415
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
1516
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
@@ -65,6 +66,8 @@ void testIssue2436() throws JSQLParserException {
6566
"SELECT a IS NULL ? 'x' : y FROM t",
6667
// jdbc parameters as branches
6768
"SELECT a ? ? : c FROM t",
69+
"SELECT a ? b + ? : c FROM t",
70+
"SELECT a ? ? : ? FROM t",
6871
"SELECT a ? b : ? FROM t",
6972
"SELECT * FROM t WHERE x = ? AND y ? z : w",
7073
// case expression inside a branch
@@ -156,6 +159,23 @@ void testTernaryWithCastThenBranch() throws JSQLParserException {
156159
Assertions.assertTrue(ternary.getThenExpression() instanceof CastExpression);
157160
}
158161

162+
@Test
163+
void testTernaryWithPositionalParameterThenBranch() throws JSQLParserException {
164+
// regression guard: a bare "?" positional parameter is a complete
165+
// expression, so the ":" after it closes the ternary instead of being
166+
// skipped in favor of the jsonb reading
167+
Select select = (Select) CCJSqlParserUtil.parse("SELECT a ? ? : c FROM t");
168+
TernaryExpression ternary = (TernaryExpression) ((PlainSelect) select).getSelectItem(0)
169+
.getExpression();
170+
Assertions.assertTrue(ternary.getThenExpression() instanceof JdbcParameter);
171+
Assertions.assertTrue(ternary.getElseExpression() instanceof Column);
172+
173+
// a positional parameter as the LAST token of the then-branch, too
174+
select = (Select) CCJSqlParserUtil.parse("SELECT a ? b + ? : c FROM t");
175+
ternary = (TernaryExpression) ((PlainSelect) select).getSelectItem(0).getExpression();
176+
Assertions.assertTrue(ternary.getThenExpression() instanceof Addition);
177+
}
178+
159179
@ParameterizedTest
160180
@ValueSource(strings = {
161181
// PostgreSQL jsonb operator combined with JDBC named parameters

0 commit comments

Comments
 (0)