Skip to content

Commit 17f5f2a

Browse files
fix: allow Parameters like $1,$2
- fixes #1970 Signed-off-by: Andreas Reichel <[email protected]>
1 parent 72a51e5 commit 17f5f2a

File tree

4 files changed

+60
-28
lines changed

4 files changed

+60
-28
lines changed

src/main/java/net/sf/jsqlparser/expression/JdbcParameter.java

+27-4
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,43 @@
1111

1212
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
1313

14+
import java.util.regex.Matcher;
15+
import java.util.regex.Pattern;
16+
1417
/**
1518
* A '?' in a statement or a ?&lt;number&gt; e.g. ?4
1619
*/
1720
public class JdbcParameter extends ASTNodeAccessImpl implements Expression {
1821

22+
private String parameterCharacter = "?";
1923
private Integer index;
2024
private boolean useFixedIndex = false;
2125

22-
public JdbcParameter() {
23-
}
26+
public JdbcParameter() {}
2427

25-
public JdbcParameter(Integer index, boolean useFixedIndex) {
28+
public JdbcParameter(Integer index, boolean useFixedIndex, String parameterCharacter) {
2629
this.index = index;
2730
this.useFixedIndex = useFixedIndex;
31+
this.parameterCharacter = parameterCharacter;
32+
33+
// This is needed for Parameters starting with "$" like "$2"
34+
// Those will contain the index in the parameterCharacter
35+
final Pattern pattern = Pattern.compile("(\\$)(\\d*)");
36+
final Matcher matcher = pattern.matcher(parameterCharacter);
37+
if (matcher.find() && matcher.groupCount() == 2) {
38+
this.useFixedIndex = true;
39+
this.parameterCharacter = matcher.group(1);
40+
this.index = Integer.valueOf(matcher.group(2));
41+
}
42+
}
43+
44+
public String getParameterCharacter() {
45+
return parameterCharacter;
46+
}
47+
48+
public JdbcParameter setParameterCharacter(String parameterCharacter) {
49+
this.parameterCharacter = parameterCharacter;
50+
return this;
2851
}
2952

3053
public Integer getIndex() {
@@ -50,7 +73,7 @@ public void accept(ExpressionVisitor expressionVisitor) {
5073

5174
@Override
5275
public String toString() {
53-
return useFixedIndex ? "?" + index : "?";
76+
return useFixedIndex ? parameterCharacter + index : parameterCharacter;
5477
}
5578

5679
public JdbcParameter withIndex(Integer index) {

src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ public void visit(IsBooleanExpression isBooleanExpression) {
328328

329329
@Override
330330
public void visit(JdbcParameter jdbcParameter) {
331-
buffer.append("?");
331+
buffer.append(jdbcParameter.getParameterCharacter());
332332
if (jdbcParameter.isUseFixedIndex()) {
333333
buffer.append(jdbcParameter.getIndex());
334334
}

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

+18-23
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,8 @@ SPECIAL_TOKEN:
530530

531531
TOKEN:
532532
{
533+
<S_PARAMETER: ["$"] (["0"-"9"])+ >
534+
|
533535
<S_IDENTIFIER: <LETTER> (<PART_LETTER>)*>
534536
| <#LETTER: <UnicodeIdentifierStart>
535537
| <Nd> | [ "$" , "#", "_" ] // Not SQL:2016 compliant!
@@ -3126,27 +3128,20 @@ OrderByElement OrderByElement():
31263128
}
31273129
}
31283130

3129-
JdbcParameter SimpleJdbcParameter() : {
3131+
JdbcParameter JdbcParameter() : {
3132+
Token tk;
31303133
JdbcParameter retval;
31313134
}
31323135
{
3133-
"?" { retval = new JdbcParameter(++jdbcParameterIndex, false); }
3134-
[ LOOKAHEAD(2) token = <S_LONG> { retval.setUseFixedIndex(true); retval.setIndex(Integer.valueOf(token.image)); } ]
3135-
{
3136-
return retval;
3137-
}
3138-
}
3136+
( tk="?" | tk=<S_PARAMETER> )
3137+
{ retval = new JdbcParameter(++jdbcParameterIndex, false, tk.image); }
31393138

3140-
JdbcNamedParameter SimpleJdbcNamedParameter() : {
3141-
String name;
3142-
}
3143-
{
3144-
":" name = RelObjectNameExt()
3145-
{
3146-
return new JdbcNamedParameter(token.image);
3147-
}
3139+
[ LOOKAHEAD(2) token = <S_LONG> { retval.setUseFixedIndex(true); retval.setIndex(Integer.valueOf(token.image)); } ]
3140+
3141+
{ return retval; }
31483142
}
31493143

3144+
31503145
Limit LimitWithOffset() #LimitWithOffset:
31513146
{
31523147
Limit limit = new Limit();
@@ -3323,7 +3318,7 @@ Top Top():
33233318
(
33243319
token=<S_LONG> { top.setExpression(new LongValue(token.image)); }
33253320
|
3326-
jdbc = SimpleJdbcParameter() { top.setExpression(jdbc); }
3321+
jdbc = JdbcParameter() { top.setExpression(jdbc); }
33273322
/*"?" { top.setExpression(new JdbcParameter(++jdbcParameterIndex, false)); } [ LOOKAHEAD(2) token = <S_LONG> { ((JdbcParameter)(top.getExpression())).setUseFixedIndex(true); ((JdbcParameter)(top.getExpression())).setIndex(Integer.valueOf(token.image)); } ]*/
33283323
|
33293324
":" { top.setExpression(new JdbcNamedParameter()); } [ LOOKAHEAD(2) token = <S_IDENTIFIER> { ((JdbcNamedParameter)top.getExpression()).setName(token.image); } ]
@@ -3354,7 +3349,7 @@ Skip Skip():
33543349
(
33553350
token=<S_LONG> { skip.setRowCount(Long.parseLong(token.image)); }
33563351
| token=<S_IDENTIFIER> { skip.setVariable(token.image); }
3357-
| jdbc = SimpleJdbcParameter() { skip.setJdbcParameter(jdbc); }
3352+
| jdbc = JdbcParameter() { skip.setJdbcParameter(jdbc); }
33583353
/* "?" { skip.setJdbcParameter(new JdbcParameter(++jdbcParameterIndex, false)); } [ LOOKAHEAD(2) token = <S_LONG> { skip.getJdbcParameter().setUseFixedIndex(true); skip.getJdbcParameter().setIndex(Integer.valueOf(token.image)); } ] */
33593354
)
33603355
{
@@ -3396,7 +3391,7 @@ First First():
33963391
|
33973392
token=<S_IDENTIFIER> { first.setVariable(token.image); }
33983393
|
3399-
jdbc = SimpleJdbcParameter() { first.setJdbcParameter(jdbc); }
3394+
jdbc = JdbcParameter() { first.setJdbcParameter(jdbc); }
34003395
)
34013396
{
34023397
return first;
@@ -4235,9 +4230,9 @@ Expression PrimaryExpression() #PrimaryExpression:
42354230

42364231
| LOOKAHEAD(3, {!interrupted}) retval=CaseWhenExpression()
42374232

4238-
| LOOKAHEAD(3) retval = SimpleJdbcParameter()
4233+
| retval = JdbcParameter()
42394234

4240-
| LOOKAHEAD(2) retval=JdbcNamedParameter()
4235+
| LOOKAHEAD(2) retval =JdbcNamedParameter()
42414236

42424237
| LOOKAHEAD(3) retval=UserVariable()
42434238

@@ -4758,7 +4753,7 @@ IntervalExpression IntervalExpression() : {
47584753
{
47594754

47604755
{ interval = new IntervalExpression(); }
4761-
<K_INTERVAL> ["-" {signed=true;}] (token=<S_LONG> | token=<S_DOUBLE> | token=<S_CHAR_LITERAL> | LOOKAHEAD(SimpleJdbcParameter()) expr = SimpleJdbcParameter() | expr = JdbcNamedParameter() | LOOKAHEAD(Function()) expr = Function() | expr = Column())
4756+
<K_INTERVAL> ["-" {signed=true;}] (token=<S_LONG> | token=<S_DOUBLE> | token=<S_CHAR_LITERAL> | LOOKAHEAD(JdbcParameter()) expr = JdbcParameter() | expr = JdbcNamedParameter() | LOOKAHEAD(Function()) expr = Function() | expr = Column())
47624757
{
47634758
if (expr != null) {
47644759
if (signed) expr = new SignedExpression('-', expr);
@@ -5099,9 +5094,9 @@ FullTextSearch FullTextSearch() : {
50995094
(
51005095
againstValue=<S_CHAR_LITERAL> { fs.setAgainstValue(new StringValue(againstValue.image)); }
51015096
|
5102-
jdbcParameter=SimpleJdbcParameter() { fs.setAgainstValue( jdbcParameter ); }
5097+
jdbcParameter=JdbcParameter() { fs.setAgainstValue( jdbcParameter ); }
51035098
|
5104-
jdbcNamedParameter=SimpleJdbcNamedParameter() { fs.setAgainstValue( jdbcNamedParameter ); }
5099+
jdbcNamedParameter=JdbcNamedParameter() { fs.setAgainstValue( jdbcNamedParameter ); }
51055100
)
51065101
[
51075102
(

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

+14
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
import net.sf.jsqlparser.JSQLParserException;
1313
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd;
14+
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
1415
import net.sf.jsqlparser.statement.select.PlainSelect;
1516
import net.sf.jsqlparser.test.TestUtils;
17+
import org.junit.jupiter.api.Assertions;
1618
import org.junit.jupiter.api.Test;
1719

1820
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -39,4 +41,16 @@ void testIssue1785() throws JSQLParserException {
3941
+ "where owner = &myowner";
4042
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
4143
}
44+
45+
@Test
46+
void testIssue1970() throws JSQLParserException {
47+
String sqlStr = "SELECT a from tbl where col = $2";
48+
PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
49+
50+
EqualsTo where = (EqualsTo) select.getWhere();
51+
Assertions.assertInstanceOf(JdbcParameter.class, where.getRightExpression());
52+
53+
JdbcParameter p = (JdbcParameter) where.getRightExpression();
54+
Assertions.assertEquals(2, p.getIndex());
55+
}
4256
}

0 commit comments

Comments
 (0)