Skip to content

Commit 9886b02

Browse files
Added ability to have operators like '>=' or '<=' separated by a space.
This includes: * Modifying the JJT syntax to support the 'space in the middle' versions of operators (any quantity of whitespace is supported). * Modifying the various operators to inherit from a new 'ComparisonOperator' class, which handles the (previously NotEqualsTo- only) logic for capturing the form of the operator. * Giving each of the various operators a constructor that accepts the syntax used. * Modifying TestUtils to strip comments out before comparing SQL text (necessary because condition07.sql is now passing, and has a comment). * Updating SpecialOracleTest to indicate 130 tests passing now (condition7.sql now passes). * Adding a new test specifically for operators into SpecialOracleTest. NOTE: Because the "! =" form of the 'not equals' operator means something different in PostgresSQL (factorial of previous argument + equals), we do NOT include that case.
1 parent 6ba57e5 commit 9886b02

File tree

10 files changed

+155
-54
lines changed

10 files changed

+155
-54
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2013 JSQLParser
6+
* %%
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Lesser General Public License as
9+
* published by the Free Software Foundation, either version 2.1 of the
10+
* License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Lesser Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Lesser Public
18+
* License along with this program. If not, see
19+
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
20+
* #L%
21+
*/
22+
package net.sf.jsqlparser.expression.operators.relational;
23+
24+
public abstract class ComparisonOperator extends OldOracleJoinBinaryExpression {
25+
26+
private final String operator;
27+
28+
public ComparisonOperator(String operator) {
29+
this.operator = operator;
30+
}
31+
32+
@Override
33+
public String getStringExpression() {
34+
return operator;
35+
}
36+
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,14 @@
2323

2424
import net.sf.jsqlparser.expression.ExpressionVisitor;
2525

26-
public class EqualsTo extends OldOracleJoinBinaryExpression {
26+
public class EqualsTo extends ComparisonOperator {
2727

28-
@Override
29-
public void accept(ExpressionVisitor expressionVisitor) {
30-
expressionVisitor.visit(this);
28+
public EqualsTo() {
29+
super("=");
3130
}
3231

3332
@Override
34-
public String getStringExpression() {
35-
return "=";
33+
public void accept(ExpressionVisitor expressionVisitor) {
34+
expressionVisitor.visit(this);
3635
}
3736
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,14 @@
2323

2424
import net.sf.jsqlparser.expression.ExpressionVisitor;
2525

26-
public class GreaterThan extends OldOracleJoinBinaryExpression {
26+
public class GreaterThan extends ComparisonOperator {
2727

28+
public GreaterThan() {
29+
super(">");
30+
}
31+
2832
@Override
2933
public void accept(ExpressionVisitor expressionVisitor) {
3034
expressionVisitor.visit(this);
3135
}
32-
33-
@Override
34-
public String getStringExpression() {
35-
return ">";
36-
}
3736
}

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,18 @@
2323

2424
import net.sf.jsqlparser.expression.ExpressionVisitor;
2525

26-
public class GreaterThanEquals extends OldOracleJoinBinaryExpression {
26+
public class GreaterThanEquals extends ComparisonOperator {
2727

28-
@Override
29-
public void accept(ExpressionVisitor expressionVisitor) {
30-
expressionVisitor.visit(this);
28+
public GreaterThanEquals() {
29+
super(">=");
30+
}
31+
32+
public GreaterThanEquals(String operator) {
33+
super(operator);
3134
}
3235

3336
@Override
34-
public String getStringExpression() {
35-
return ">=";
37+
public void accept(ExpressionVisitor expressionVisitor) {
38+
expressionVisitor.visit(this);
3639
}
3740
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,14 @@
2323

2424
import net.sf.jsqlparser.expression.ExpressionVisitor;
2525

26-
public class MinorThan extends OldOracleJoinBinaryExpression {
26+
public class MinorThan extends ComparisonOperator {
2727

28-
@Override
29-
public void accept(ExpressionVisitor expressionVisitor) {
30-
expressionVisitor.visit(this);
28+
public MinorThan() {
29+
super("<");
3130
}
3231

3332
@Override
34-
public String getStringExpression() {
35-
return "<";
33+
public void accept(ExpressionVisitor expressionVisitor) {
34+
expressionVisitor.visit(this);
3635
}
3736
}

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,18 @@
2323

2424
import net.sf.jsqlparser.expression.ExpressionVisitor;
2525

26-
public class MinorThanEquals extends OldOracleJoinBinaryExpression {
26+
public class MinorThanEquals extends ComparisonOperator {
2727

28-
@Override
29-
public void accept(ExpressionVisitor expressionVisitor) {
30-
expressionVisitor.visit(this);
28+
public MinorThanEquals() {
29+
super("<=");
30+
}
31+
32+
public MinorThanEquals(String operator) {
33+
super(operator);
3134
}
3235

3336
@Override
34-
public String getStringExpression() {
35-
return "<=";
37+
public void accept(ExpressionVisitor expressionVisitor) {
38+
expressionVisitor.visit(this);
3639
}
3740
}

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

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,18 @@
2323

2424
import net.sf.jsqlparser.expression.ExpressionVisitor;
2525

26-
public class NotEqualsTo extends OldOracleJoinBinaryExpression {
27-
28-
private final String operator;
26+
public class NotEqualsTo extends ComparisonOperator {
2927

3028
public NotEqualsTo() {
31-
operator = "<>";
29+
super("<>");
3230
}
3331

3432
public NotEqualsTo(String operator) {
35-
this.operator = operator;
36-
if (!"!=".equals(operator) && !"<>".equals(operator)) {
37-
throw new IllegalArgumentException("only <> or != allowed");
38-
}
33+
super(operator);
3934
}
4035

4136
@Override
4237
public void accept(ExpressionVisitor expressionVisitor) {
4338
expressionVisitor.visit(this);
4439
}
45-
46-
@Override
47-
public String getStringExpression() {
48-
return operator;
49-
}
5040
}

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

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,7 @@ PARSER_END(CCJSqlParser)
9595

9696
SKIP:
9797
{
98-
" "
99-
| "\t"
100-
| "\r"
101-
| "\n"
98+
<WHITESPACE: " " | "\t" | "\r" | "\n">
10299
}
103100

104101
TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
@@ -237,6 +234,14 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
237234
| <K_IGNORE : "IGNORE">
238235
}
239236

237+
TOKEN : /* Operators */
238+
{
239+
<OP_GREATERTHANEQUALS: ">" (<WHITESPACE>)* "=">
240+
| <OP_MINORTHANEQUALS: "<" (<WHITESPACE>)* "=">
241+
| <OP_NOTEQUALSSTANDARD: "<" (<WHITESPACE>)* ">">
242+
| <OP_NOTEQUALSBANG: "!=">
243+
}
244+
240245
TOKEN : /* Numeric Constants */
241246
{
242247
< S_DOUBLE: ((<S_LONG>)? "." <S_LONG> ( ["e","E"] (["+", "-"])? <S_LONG>)?
@@ -1611,14 +1616,14 @@ Expression RegularCondition():
16111616

16121617
[ "(" "+" ")" { oracleJoin=EqualsTo.ORACLE_JOIN_RIGHT; } ]
16131618

1614-
(
1619+
( LOOKAHEAD(2)
16151620
">" { result = new GreaterThan(); }
16161621
| "<" { result = new MinorThan(); }
16171622
| "=" { result = new EqualsTo(); }
1618-
| ">=" { result = new GreaterThanEquals(); }
1619-
| "<=" { result = new MinorThanEquals(); }
1620-
| "<>" { result = new NotEqualsTo(); }
1621-
| "!=" { result = new NotEqualsTo("!="); }
1623+
| token=<OP_GREATERTHANEQUALS> { result = new GreaterThanEquals(token.image); }
1624+
| token=<OP_MINORTHANEQUALS> { result = new MinorThanEquals(token.image); }
1625+
| token=<OP_NOTEQUALSSTANDARD> { result = new NotEqualsTo(token.image); }
1626+
| token=<OP_NOTEQUALSBANG> { result = new NotEqualsTo(token.image); }
16221627
| "@@" { result = new Matches(); }
16231628
| "~" { result = new RegExpMatchOperator(RegExpMatchOperatorType.MATCH_CASESENSITIVE); }
16241629
| <K_REGEXP> [ <K_BINARY> { binary=true; } ] { result = new RegExpMySQLOperator(binary?RegExpMatchOperatorType.MATCH_CASESENSITIVE:RegExpMatchOperatorType.MATCH_CASEINSENSITIVE); }

src/test/java/net/sf/jsqlparser/test/TestUtils.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import net.sf.jsqlparser.util.deparser.*;
2626

2727
import java.io.*;
28+
import java.util.regex.Pattern;
2829

2930
import static junit.framework.Assert.assertEquals;
3031
import static junit.framework.TestCase.assertEquals;
@@ -42,6 +43,8 @@
4243
*/
4344
public class TestUtils {
4445

46+
private static final Pattern SQL_COMMENT_PATTERN = Pattern.compile("(--.*$)|(/\\*.*?\\*/)",Pattern.MULTILINE);
47+
4548
public static void assertSqlCanBeParsedAndDeparsed(String statement) throws JSQLParserException {
4649
assertSqlCanBeParsedAndDeparsed(statement, false);
4750
}
@@ -72,8 +75,9 @@ public static void assertStatementCanBeDeparsedAs(Statement parsed, String state
7275
assertEquals(buildSqlString(statement, laxDeparsingCheck),
7376
buildSqlString(deParser.getBuffer().toString(), laxDeparsingCheck));
7477
}
75-
78+
7679
public static String buildSqlString(String sql, boolean laxDeparsingCheck) {
80+
sql = SQL_COMMENT_PATTERN.matcher(sql).replaceAll("");
7781
if (laxDeparsingCheck) {
7882
return sql.replaceAll("\\s", " ").replaceAll("\\s+", " ").replaceAll("\\s*([/,()=+\\-*|\\]<>])\\s*", "$1").toLowerCase().trim();
7983
} else {

src/test/java/net/sf/jsqlparser/test/select/SpecialOracleTest.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
import java.util.logging.Logger;
2525
import net.sf.jsqlparser.JSQLParserException;
2626
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
27+
import net.sf.jsqlparser.statement.Statement;
28+
import net.sf.jsqlparser.parser.TokenMgrError;
29+
2730
import static net.sf.jsqlparser.test.TestUtils.*;
2831
import org.apache.commons.io.FileUtils;
2932
import static org.junit.Assert.assertTrue;
@@ -63,14 +66,17 @@ public void testAllSqlsParseDeparse() throws IOException {
6366
} catch (JSQLParserException ex) {
6467
//LOG.log(Level.SEVERE, null, ex);
6568
LOG.log(Level.INFO, " -> PROBLEM {0}", ex.toString());
69+
} catch (TokenMgrError ex) {
70+
//LOG.log(Level.SEVERE, null, ex);
71+
LOG.log(Level.INFO, " -> PROBLEM {0}", ex.toString());
6672
} catch (Exception ex) {
6773
LOG.log(Level.INFO, " -> PROBLEM {0}", ex.toString());
6874
}
6975
}
7076
}
7177

7278
LOG.log(Level.INFO, "tested {0} files. got {1} correct parse results", new Object[]{count, success});
73-
assertTrue(success >= 129);
79+
assertTrue(success >= 130);
7480
}
7581

7682
@Test
@@ -89,4 +95,61 @@ public void testAllSqlsOnlyParse() throws IOException {
8995
}
9096
}
9197
}
98+
99+
@Test
100+
public void testOperatorsWithSpaces() throws Exception {
101+
String sql;
102+
Statement statement;
103+
104+
// First, the regular way (normal for most databases).
105+
sql = "SELECT\n"
106+
+ " Something\n"
107+
+ "FROM\n"
108+
+ " Sometable\n"
109+
+ "WHERE\n"
110+
+ " Somefield >= Somevalue\n"
111+
+ " AND Somefield <= Somevalue\n"
112+
+ " AND Somefield <> Somevalue\n"
113+
+ " AND Somefield != Somevalue\n";
114+
115+
statement = CCJSqlParserUtil.parse(sql);
116+
117+
System.out.println(statement.toString());
118+
119+
assertSqlCanBeParsedAndDeparsed(sql, true);
120+
121+
// Second, the special crap Oracle lets you get away with.
122+
sql = "SELECT\n"
123+
+ " Something\n"
124+
+ "FROM\n"
125+
+ " Sometable\n"
126+
+ "WHERE\n"
127+
+ " Somefield > = Somevalue\n"
128+
+ " AND Somefield < = Somevalue\n"
129+
+ " AND Somefield < > Somevalue\n";
130+
131+
// Note, we do not (currently) test the "!=" with spaces in between -- Postgresql deals with this as two operators, "factorial" and "equals".
132+
133+
statement = CCJSqlParserUtil.parse(sql);
134+
135+
System.out.println(statement.toString());
136+
137+
assertSqlCanBeParsedAndDeparsed(sql, true);
138+
139+
// And then with multiple whitespace
140+
sql = "SELECT\n"
141+
+ " Something\n"
142+
+ "FROM\n"
143+
+ " Sometable\n"
144+
+ "WHERE\n"
145+
+ " Somefield > \t = Somevalue\n"
146+
+ " AND Somefield < = Somevalue\n"
147+
+ " AND Somefield <\t\t> Somevalue\n";
148+
149+
statement = CCJSqlParserUtil.parse(sql);
150+
151+
System.out.println(statement.toString());
152+
153+
assertSqlCanBeParsedAndDeparsed(sql, true);
154+
}
92155
}

0 commit comments

Comments
 (0)