Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,9 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
* in operand position instead (directly after an operator, e.g. `x = :name`
* or directly after the leading "?") starts a JDBC named parameter.
* DATA_TYPE tokens end expressions as well, because a cast's target type
* (`b :: int`) or a bare type keyword closes the then-branch.
* (`b :: int`) or a bare type keyword closes the then-branch. The bare "?"
* positional parameter has no token-kind constant (anonymous token), so it
* is recognized by its image, like the closing brackets.
*/
private boolean canEndExpression(Token t) {
if (t == null) {
Expand All @@ -294,7 +296,8 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
return true;
default:
return (t.kind >= MIN_NON_RESERVED_WORD && t.kind <= MAX_NON_RESERVED_WORD)
|| ")".equals(t.image) || "]".equals(t.image);
|| ")".equals(t.image) || "]".equals(t.image)
|| "?".equals(t.image);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package net.sf.jsqlparser.expression;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
Expand Down Expand Up @@ -65,6 +66,8 @@ void testIssue2436() throws JSQLParserException {
"SELECT a IS NULL ? 'x' : y FROM t",
// jdbc parameters as branches
"SELECT a ? ? : c FROM t",
"SELECT a ? b + ? : c FROM t",
"SELECT a ? ? : ? FROM t",
"SELECT a ? b : ? FROM t",
"SELECT * FROM t WHERE x = ? AND y ? z : w",
// case expression inside a branch
Expand Down Expand Up @@ -156,6 +159,23 @@ void testTernaryWithCastThenBranch() throws JSQLParserException {
Assertions.assertTrue(ternary.getThenExpression() instanceof CastExpression);
}

@Test
void testTernaryWithPositionalParameterThenBranch() throws JSQLParserException {
// regression guard: a bare "?" positional parameter is a complete
// expression, so the ":" after it closes the ternary instead of being
// skipped in favor of the jsonb reading
Select select = (Select) CCJSqlParserUtil.parse("SELECT a ? ? : c FROM t");
TernaryExpression ternary = (TernaryExpression) ((PlainSelect) select).getSelectItem(0)
.getExpression();
Assertions.assertTrue(ternary.getThenExpression() instanceof JdbcParameter);
Assertions.assertTrue(ternary.getElseExpression() instanceof Column);

// a positional parameter as the LAST token of the then-branch, too
select = (Select) CCJSqlParserUtil.parse("SELECT a ? b + ? : c FROM t");
ternary = (TernaryExpression) ((PlainSelect) select).getSelectItem(0).getExpression();
Assertions.assertTrue(ternary.getThenExpression() instanceof Addition);
}

@ParameterizedTest
@ValueSource(strings = {
// PostgreSQL jsonb operator combined with JDBC named parameters
Expand Down
Loading