Skip to content

Commit c423224

Browse files
IN() with complex expressions (#1384)
* IN() with Complex Expressions Fixes #905 Allow Complex Expressions and multiple SubSelects for the IN() Expression * Tune the Test Coverage * Remove unused import * Reset TEST status
1 parent 8c1eba2 commit c423224

File tree

10 files changed

+105
-87
lines changed

10 files changed

+105
-87
lines changed

build.gradle

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,63 @@ jacocoTestReport {
7171
jacocoTestCoverageVerification {
7272
violationRules {
7373
rule {
74+
//element = 'CLASS'
7475
limit {
75-
minimum = JavaVersion.current().isJava8() // for any reason, different results
76-
? 0.83 // depending on the Java Version
77-
: 0.842
76+
minimum = 0.84
7877
}
78+
excludes = [
79+
'net.sf.jsqlparser.util.validation.*',
80+
'net.sf.jsqlparser.**.*Adapter',
81+
'net.sf.jsqlparser.parser.JJTCCJSqlParserState',
82+
'net.sf.jsqlparser.parser.TokenMgrError',
83+
'net.sf.jsqlparser.parser.StreamProvider',
84+
'net.sf.jsqlparser.parser.CCJSqlParserTokenManager',
85+
'net.sf.jsqlparser.parser.ParseException',
86+
'net.sf.jsqlparser.parser.SimpleNode',
87+
'net.sf.jsqlparser.parser.SimpleCharStream',
88+
'net.sf.jsqlparser.parser.StringProvider',
89+
]
90+
}
91+
rule {
92+
//element = 'CLASS'
93+
limit {
94+
counter = 'LINE'
95+
value = 'MISSEDCOUNT'
96+
maximum = 5458
97+
}
98+
excludes = [
99+
'net.sf.jsqlparser.util.validation.*',
100+
'net.sf.jsqlparser.**.*Adapter',
101+
'net.sf.jsqlparser.parser.JJTCCJSqlParserState',
102+
'net.sf.jsqlparser.parser.TokenMgrError',
103+
'net.sf.jsqlparser.parser.StreamProvider',
104+
'net.sf.jsqlparser.parser.CCJSqlParserTokenManager',
105+
'net.sf.jsqlparser.parser.ParseException',
106+
'net.sf.jsqlparser.parser.SimpleNode',
107+
'net.sf.jsqlparser.parser.SimpleCharStream',
108+
'net.sf.jsqlparser.parser.StringProvider',
109+
]
79110
}
111+
// rule {
112+
// element = 'CLASS'
113+
// limit {
114+
// counter = 'LINE'
115+
// value = 'MISSEDRATIO'
116+
// maximum = 0.3
117+
// }
118+
// excludes = [
119+
// 'net.sf.jsqlparser.util.validation.*',
120+
// 'net.sf.jsqlparser.**.*Adapter',
121+
// 'net.sf.jsqlparser.parser.JJTCCJSqlParserState',
122+
// 'net.sf.jsqlparser.parser.TokenMgrError',
123+
// 'net.sf.jsqlparser.parser.StreamProvider',
124+
// 'net.sf.jsqlparser.parser.CCJSqlParserTokenManager',
125+
// 'net.sf.jsqlparser.parser.ParseException',
126+
// 'net.sf.jsqlparser.parser.SimpleNode',
127+
// 'net.sf.jsqlparser.parser.SimpleCharStream',
128+
// 'net.sf.jsqlparser.parser.StringProvider',
129+
// ]
130+
// }
80131
}
81132
}
82133

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,6 @@ public void visit(InExpression expr) {
185185
expr.getRightExpression().accept(this);
186186
} else if (expr.getRightItemsList() != null) {
187187
expr.getRightItemsList().accept(this);
188-
} else {
189-
expr.getMultiExpressionList().accept(this);
190188
}
191189
}
192190

src/main/java/net/sf/jsqlparser/expression/operators/relational/InExpression.java

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ public class InExpression extends ASTNodeAccessImpl implements Expression, Suppo
1919
private ItemsList rightItemsList;
2020
private boolean not = false;
2121
private Expression rightExpression;
22-
private MultiExpressionList multiExpressionList;
23-
2422
private int oldOracleJoinSyntax = NO_ORACLE_JOIN;
2523

2624
public InExpression() {
@@ -105,21 +103,12 @@ public String toString() {
105103
if (not) {
106104
statementBuilder.append("NOT ");
107105
}
108-
109106
statementBuilder.append("IN ");
110-
111-
if (multiExpressionList != null) {
112-
statementBuilder.append("(");
113-
statementBuilder.append(multiExpressionList);
114-
statementBuilder.append(")");
107+
if (rightExpression == null) {
108+
statementBuilder.append(rightItemsList);
115109
} else {
116-
if (rightExpression == null) {
117-
statementBuilder.append(rightItemsList);
118-
} else {
119-
statementBuilder.append(rightExpression);
120-
}
110+
statementBuilder.append(rightExpression);
121111
}
122-
123112
return statementBuilder.toString();
124113
}
125114

@@ -135,24 +124,11 @@ public void setOraclePriorPosition(int priorPosition) {
135124
}
136125
}
137126

138-
public MultiExpressionList getMultiExpressionList() {
139-
return multiExpressionList;
140-
}
141-
142-
public void setMultiExpressionList(MultiExpressionList multiExpressionList) {
143-
this.multiExpressionList = multiExpressionList;
144-
}
145-
146127
public InExpression withRightExpression(Expression rightExpression) {
147128
this.setRightExpression(rightExpression);
148129
return this;
149130
}
150131

151-
public InExpression withMultiExpressionList(MultiExpressionList multiExpressionList) {
152-
this.setMultiExpressionList(multiExpressionList);
153-
return this;
154-
}
155-
156132
@Override
157133
public InExpression withOldOracleJoinSyntax(int oldOracleJoinSyntax) {
158134
this.setOldOracleJoinSyntax(oldOracleJoinSyntax);

src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,6 @@ public void visit(InExpression inExpression) {
242242
inExpression.getRightExpression().accept(this);
243243
} else if (inExpression.getRightItemsList() != null) {
244244
inExpression.getRightItemsList().accept(this);
245-
} else {
246-
inExpression.getMultiExpressionList().accept(this);
247245
}
248246
}
249247

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

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -186,41 +186,13 @@ public void visit(InExpression inExpression) {
186186
buffer.append(" NOT");
187187
}
188188
buffer.append(" IN ");
189-
190-
if (inExpression.getMultiExpressionList() != null) {
191-
parseMultiExpressionList(inExpression);
189+
if (inExpression.getRightExpression() != null) {
190+
inExpression.getRightExpression().accept(this);
192191
} else {
193-
if (inExpression.getRightExpression() != null) {
194-
inExpression.getRightExpression().accept(this);
195-
} else {
196-
inExpression.getRightItemsList().accept(this);
197-
}
192+
inExpression.getRightItemsList().accept(this);
198193
}
199194
}
200195

201-
/**
202-
* Produces a multi-expression in clause: {@code ((a, b), (c, d))}
203-
*/
204-
private void parseMultiExpressionList(InExpression inExpression) {
205-
MultiExpressionList multiExprList = inExpression.getMultiExpressionList();
206-
buffer.append("(");
207-
for (Iterator<ExpressionList> it = multiExprList.getExprList().iterator(); it.hasNext();) {
208-
buffer.append("(");
209-
for (Iterator<Expression> iter = it.next().getExpressions().iterator(); iter.hasNext();) {
210-
Expression expression = iter.next();
211-
expression.accept(this);
212-
if (iter.hasNext()) {
213-
buffer.append(", ");
214-
}
215-
}
216-
buffer.append(")");
217-
if (it.hasNext()) {
218-
buffer.append(", ");
219-
}
220-
}
221-
buffer.append(")");
222-
}
223-
224196
@Override
225197
public void visit(FullTextSearch fullTextSearch) {
226198
// Build a list of matched columns

src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,6 @@ public void visit(InExpression inExpression) {
149149
validateFeature(c, Feature.oracleOldJoinSyntax);
150150
}
151151
}
152-
153-
validateOptionalMultiExpressionList(inExpression.getMultiExpressionList());
154152
validateOptionalExpression(inExpression.getRightExpression(), this);
155153
validateOptionalItemsList(inExpression.getRightItemsList());
156154
}

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

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2924,7 +2924,7 @@ Expression XorExpression():
29242924
}
29252925
{
29262926
left=OrExpression() { result = left; }
2927-
(
2927+
( LOOKAHEAD(2)
29282928
<K_XOR>
29292929
right=OrExpression()
29302930
{
@@ -2943,7 +2943,7 @@ Expression OrExpression():
29432943
}
29442944
{
29452945
left=AndExpression() { result = left; }
2946-
(
2946+
( LOOKAHEAD(2)
29472947
<K_OR>
29482948
right=AndExpression()
29492949
{
@@ -2973,7 +2973,7 @@ Expression AndExpression() :
29732973
)
29742974
{ result = left; }
29752975

2976-
(
2976+
( LOOKAHEAD(2)
29772977
{ boolean useOperator = false; }
29782978
(<K_AND> | <K_AND_OPERATOR> {useOperator=true;} )
29792979
(
@@ -3100,7 +3100,7 @@ Expression InExpression() #InExpression :
31003100
{
31013101
InExpression result = new InExpression();
31023102
ItemsList leftItemsList = null;
3103-
ItemsList rightItemsList = null;
3103+
ExpressionList rightItemsList = null;
31043104
Expression leftExpression = null;
31053105
Expression rightExpression = null;
31063106
Token token;
@@ -3113,17 +3113,13 @@ Expression InExpression() #InExpression :
31133113

31143114
[<K_NOT> { result.setNot(true); } ] <K_IN>
31153115
(
3116-
// syntactic lookahead for a multi expression list, ie: ((a,b),(c,d))
3117-
LOOKAHEAD(3) multiExpressionList = MultiInExpressions()
3118-
| LOOKAHEAD(3) rightExpression = Function()
3119-
| LOOKAHEAD(2) token=<S_CHAR_LITERAL> { rightExpression = new StringValue(token.image); }
3120-
| LOOKAHEAD(3) "(" (LOOKAHEAD(3) rightItemsList=SubSelect() | rightItemsList=SimpleExpressionList(true) )")"
3121-
| rightExpression = SimpleExpression()
3116+
LOOKAHEAD(2) token=<S_CHAR_LITERAL> { result.setRightExpression(new StringValue(token.image)); }
3117+
| LOOKAHEAD(3) rightExpression = Function() { result.setRightExpression(rightExpression); }
3118+
| LOOKAHEAD( "(" ComplexExpressionList() ")" ) "(" rightItemsList=ComplexExpressionList() { result.setRightItemsList(rightItemsList.withBrackets(true) ); } ")"
3119+
| LOOKAHEAD(3) "(" rightExpression = SubSelect() { result.setRightExpression( ((SubSelect) rightExpression).withUseBrackets(true) ); } ")"
3120+
| LOOKAHEAD(2) rightExpression = SimpleExpression() { result.setRightExpression(rightExpression); }
31223121
)
31233122
{
3124-
result.setRightItemsList(rightItemsList);
3125-
result.setRightExpression(rightExpression);
3126-
result.setMultiExpressionList(multiExpressionList);
31273123
linkAST(result,jjtThis);
31283124
return result;
31293125
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import java.util.List;
1414

1515
import net.sf.jsqlparser.expression.operators.conditional.XorExpression;
16+
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
17+
import net.sf.jsqlparser.statement.select.SubSelect;
1618
import org.junit.After;
1719
import org.junit.AfterClass;
1820
import org.junit.Before;
@@ -24,7 +26,6 @@
2426
import static org.junit.Assert.fail;
2527
import net.sf.jsqlparser.JSQLParserException;
2628
import net.sf.jsqlparser.expression.operators.relational.InExpression;
27-
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
2829
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
2930
import net.sf.jsqlparser.schema.Column;
3031
import net.sf.jsqlparser.statement.select.PlainSelect;
@@ -72,7 +73,7 @@ public void visit(InExpression expr) {
7273
});
7374

7475
assertTrue(exprList.get(0) instanceof Expression);
75-
assertTrue(exprList.get(1) instanceof ItemsList);
76+
assertTrue(exprList.get(1) instanceof ExpressionList);
7677
}
7778

7879
@Test
@@ -88,12 +89,12 @@ public void testInExpression() throws JSQLParserException {
8889
public void visit(InExpression expr) {
8990
super.visit(expr);
9091
exprList.add(expr.getLeftExpression());
91-
exprList.add(expr.getRightItemsList());
92+
exprList.add(expr.getRightExpression());
9293
}
9394
});
9495

9596
assertTrue(exprList.get(0) instanceof RowConstructor);
96-
assertTrue(exprList.get(1) instanceof ItemsList);
97+
assertTrue(exprList.get(1) instanceof SubSelect);
9798
}
9899

99100
@Test

src/test/java/net/sf/jsqlparser/statement/builder/JSQLParserFluentModelTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ public void testParseAndBuild() throws JSQLParserException {
5959
)).withRightExpression(
6060
new InExpression()
6161
.withLeftExpression(new Column(asList("t1", "col3")))
62-
.withRightItemsList(new ExpressionList().addExpressions(new StringValue("A"))));
62+
.withRightItemsList(new ExpressionList(new StringValue("A"))));
63+
6364
Select select = new Select().withSelectBody(new PlainSelect().addSelectItems(new AllColumns()).withFromItem(t1)
6465
.addJoins(new Join().withRightItem(t2)
6566
.withOnExpression(
@@ -95,8 +96,7 @@ public void testParseAndBuildForXOR() throws JSQLParserException {
9596
.withRightExpression(
9697
new InExpression()
9798
.withLeftExpression(new Column(asList("t1", "col3")))
98-
.withRightItemsList(new ExpressionList()
99-
.addExpressions(new StringValue("B"), new StringValue("C")))))
99+
.withRightItemsList(new ExpressionList(new StringValue("B"), new StringValue("C")))))
100100
.withRightExpression(new Column(asList("t2", "col4")));
101101

102102
Select select = new Select().withSelectBody(new PlainSelect().addSelectItems(new AllColumns()).withFromItem(t1)

src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4889,4 +4889,32 @@ public void testCanCallSubSelectOnWithItemEvenIfNotSetIssue1369() {
48894889
WithItem item = new WithItem();
48904890
assertThat(item.getSubSelect()).isNull();
48914891
}
4892+
4893+
@Test
4894+
public void testComplexInExpressionIssue905() throws JSQLParserException {
4895+
assertSqlCanBeParsedAndDeparsed(
4896+
"select * " +
4897+
"from table_a " +
4898+
"where other_id in (" +
4899+
" (select id from table_b where name like '%aa%')" +
4900+
" , (select id from table_b where name like '%bb%')" +
4901+
")", true);
4902+
4903+
assertSqlCanBeParsedAndDeparsed(
4904+
"select * from v.e\n" +
4905+
"where\n" +
4906+
"\tcid <> rid\n" +
4907+
"\tand rid not in\n" +
4908+
"\t(\n" +
4909+
"\t\t(select distinct rid from v.s )\n" +
4910+
"\t\tunion\n" +
4911+
"\t\t(select distinct rid from v.p )\n" +
4912+
"\t)\n" +
4913+
"\tand \"timestamp\" <= 1298505600000", true);
4914+
4915+
assertSqlCanBeParsedAndDeparsed(
4916+
"select * " +
4917+
"from table_a " +
4918+
"where (a, b, c) in ((1, 2, 3), (3, 4, 5))", true);
4919+
}
48924920
}

0 commit comments

Comments
 (0)