Skip to content

Commit

Permalink
Merge pull request #258 from davelindquist-egistix/whitespace-inside-…
Browse files Browse the repository at this point in the history
…oracle-operators

Supporting Oracle operators like '>=' or '<=' with embedded whitespace.
  • Loading branch information
wumpz committed May 6, 2016
2 parents 5714516 + 9886b02 commit 0073d11
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2013 JSQLParser
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/
package net.sf.jsqlparser.expression.operators.relational;

public abstract class ComparisonOperator extends OldOracleJoinBinaryExpression {

private final String operator;

public ComparisonOperator(String operator) {
this.operator = operator;
}

@Override
public String getStringExpression() {
return operator;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@

import net.sf.jsqlparser.expression.ExpressionVisitor;

public class EqualsTo extends OldOracleJoinBinaryExpression {
public class EqualsTo extends ComparisonOperator {

@Override
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
public EqualsTo() {
super("=");
}

@Override
public String getStringExpression() {
return "=";
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@

import net.sf.jsqlparser.expression.ExpressionVisitor;

public class GreaterThan extends OldOracleJoinBinaryExpression {
public class GreaterThan extends ComparisonOperator {

public GreaterThan() {
super(">");
}

@Override
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
}

@Override
public String getStringExpression() {
return ">";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@

import net.sf.jsqlparser.expression.ExpressionVisitor;

public class GreaterThanEquals extends OldOracleJoinBinaryExpression {
public class GreaterThanEquals extends ComparisonOperator {

@Override
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
public GreaterThanEquals() {
super(">=");
}

public GreaterThanEquals(String operator) {
super(operator);
}

@Override
public String getStringExpression() {
return ">=";
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@

import net.sf.jsqlparser.expression.ExpressionVisitor;

public class MinorThan extends OldOracleJoinBinaryExpression {
public class MinorThan extends ComparisonOperator {

@Override
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
public MinorThan() {
super("<");
}

@Override
public String getStringExpression() {
return "<";
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@

import net.sf.jsqlparser.expression.ExpressionVisitor;

public class MinorThanEquals extends OldOracleJoinBinaryExpression {
public class MinorThanEquals extends ComparisonOperator {

@Override
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
public MinorThanEquals() {
super("<=");
}

public MinorThanEquals(String operator) {
super(operator);
}

@Override
public String getStringExpression() {
return "<=";
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,18 @@

import net.sf.jsqlparser.expression.ExpressionVisitor;

public class NotEqualsTo extends OldOracleJoinBinaryExpression {

private final String operator;
public class NotEqualsTo extends ComparisonOperator {

public NotEqualsTo() {
operator = "<>";
super("<>");
}

public NotEqualsTo(String operator) {
this.operator = operator;
if (!"!=".equals(operator) && !"<>".equals(operator)) {
throw new IllegalArgumentException("only <> or != allowed");
}
super(operator);
}

@Override
public void accept(ExpressionVisitor expressionVisitor) {
expressionVisitor.visit(this);
}

@Override
public String getStringExpression() {
return operator;
}
}
23 changes: 14 additions & 9 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,7 @@ PARSER_END(CCJSqlParser)

SKIP:
{
" "
| "\t"
| "\r"
| "\n"
<WHITESPACE: " " | "\t" | "\r" | "\n">
}

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

TOKEN : /* Operators */
{
<OP_GREATERTHANEQUALS: ">" (<WHITESPACE>)* "=">
| <OP_MINORTHANEQUALS: "<" (<WHITESPACE>)* "=">
| <OP_NOTEQUALSSTANDARD: "<" (<WHITESPACE>)* ">">
| <OP_NOTEQUALSBANG: "!=">
}

TOKEN : /* Numeric Constants */
{
< S_DOUBLE: ((<S_LONG>)? "." <S_LONG> ( ["e","E"] (["+", "-"])? <S_LONG>)?
Expand Down Expand Up @@ -1611,14 +1616,14 @@ Expression RegularCondition():

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

(
( LOOKAHEAD(2)
">" { result = new GreaterThan(); }
| "<" { result = new MinorThan(); }
| "=" { result = new EqualsTo(); }
| ">=" { result = new GreaterThanEquals(); }
| "<=" { result = new MinorThanEquals(); }
| "<>" { result = new NotEqualsTo(); }
| "!=" { result = new NotEqualsTo("!="); }
| token=<OP_GREATERTHANEQUALS> { result = new GreaterThanEquals(token.image); }
| token=<OP_MINORTHANEQUALS> { result = new MinorThanEquals(token.image); }
| token=<OP_NOTEQUALSSTANDARD> { result = new NotEqualsTo(token.image); }
| token=<OP_NOTEQUALSBANG> { result = new NotEqualsTo(token.image); }
| "@@" { result = new Matches(); }
| "~" { result = new RegExpMatchOperator(RegExpMatchOperatorType.MATCH_CASESENSITIVE); }
| <K_REGEXP> [ <K_BINARY> { binary=true; } ] { result = new RegExpMySQLOperator(binary?RegExpMatchOperatorType.MATCH_CASESENSITIVE:RegExpMatchOperatorType.MATCH_CASEINSENSITIVE); }
Expand Down
6 changes: 5 additions & 1 deletion src/test/java/net/sf/jsqlparser/test/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import net.sf.jsqlparser.util.deparser.*;

import java.io.*;
import java.util.regex.Pattern;

import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertEquals;
Expand All @@ -42,6 +43,8 @@
*/
public class TestUtils {

private static final Pattern SQL_COMMENT_PATTERN = Pattern.compile("(--.*$)|(/\\*.*?\\*/)",Pattern.MULTILINE);

public static void assertSqlCanBeParsedAndDeparsed(String statement) throws JSQLParserException {
assertSqlCanBeParsedAndDeparsed(statement, false);
}
Expand Down Expand Up @@ -72,8 +75,9 @@ public static void assertStatementCanBeDeparsedAs(Statement parsed, String state
assertEquals(buildSqlString(statement, laxDeparsingCheck),
buildSqlString(deParser.getBuffer().toString(), laxDeparsingCheck));
}

public static String buildSqlString(String sql, boolean laxDeparsingCheck) {
sql = SQL_COMMENT_PATTERN.matcher(sql).replaceAll("");
if (laxDeparsingCheck) {
return sql.replaceAll("\\s", " ").replaceAll("\\s+", " ").replaceAll("\\s*([/,()=+\\-*|\\]<>])\\s*", "$1").toLowerCase().trim();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import java.util.logging.Logger;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.parser.TokenMgrError;

import static net.sf.jsqlparser.test.TestUtils.*;
import org.apache.commons.io.FileUtils;
import static org.junit.Assert.assertTrue;
Expand Down Expand Up @@ -63,14 +66,17 @@ public void testAllSqlsParseDeparse() throws IOException {
} catch (JSQLParserException ex) {
//LOG.log(Level.SEVERE, null, ex);
LOG.log(Level.INFO, " -> PROBLEM {0}", ex.toString());
} catch (TokenMgrError ex) {
//LOG.log(Level.SEVERE, null, ex);
LOG.log(Level.INFO, " -> PROBLEM {0}", ex.toString());
} catch (Exception ex) {
LOG.log(Level.INFO, " -> PROBLEM {0}", ex.toString());
}
}
}

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

@Test
Expand All @@ -89,4 +95,61 @@ public void testAllSqlsOnlyParse() throws IOException {
}
}
}

@Test
public void testOperatorsWithSpaces() throws Exception {
String sql;
Statement statement;

// First, the regular way (normal for most databases).
sql = "SELECT\n"
+ " Something\n"
+ "FROM\n"
+ " Sometable\n"
+ "WHERE\n"
+ " Somefield >= Somevalue\n"
+ " AND Somefield <= Somevalue\n"
+ " AND Somefield <> Somevalue\n"
+ " AND Somefield != Somevalue\n";

statement = CCJSqlParserUtil.parse(sql);

System.out.println(statement.toString());

assertSqlCanBeParsedAndDeparsed(sql, true);

// Second, the special crap Oracle lets you get away with.
sql = "SELECT\n"
+ " Something\n"
+ "FROM\n"
+ " Sometable\n"
+ "WHERE\n"
+ " Somefield > = Somevalue\n"
+ " AND Somefield < = Somevalue\n"
+ " AND Somefield < > Somevalue\n";

// Note, we do not (currently) test the "!=" with spaces in between -- Postgresql deals with this as two operators, "factorial" and "equals".

statement = CCJSqlParserUtil.parse(sql);

System.out.println(statement.toString());

assertSqlCanBeParsedAndDeparsed(sql, true);

// And then with multiple whitespace
sql = "SELECT\n"
+ " Something\n"
+ "FROM\n"
+ " Sometable\n"
+ "WHERE\n"
+ " Somefield > \t = Somevalue\n"
+ " AND Somefield < = Somevalue\n"
+ " AND Somefield <\t\t> Somevalue\n";

statement = CCJSqlParserUtil.parse(sql);

System.out.println(statement.toString());

assertSqlCanBeParsedAndDeparsed(sql, true);
}
}

0 comments on commit 0073d11

Please sign in to comment.