Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supporting Oracle operators like '>=' or '<=' with embedded whitespace. #258

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
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);
}
}