From 68a4d9233575325797c422370d327a02d426b8f6 Mon Sep 17 00:00:00 2001 From: Rob Audenaerde Date: Thu, 4 Aug 2022 10:23:20 +0200 Subject: [PATCH] Closes #1604, added simple OVERLAPS support --- .../expression/ExpressionVisitor.java | 2 + .../expression/ExpressionVisitorAdapter.java | 6 +++ .../expression/OverlapsCondition.java | 47 +++++++++++++++++++ .../sf/jsqlparser/util/TablesNamesFinder.java | 6 +++ .../util/deparser/ExpressionDeParser.java | 5 ++ .../validator/ExpressionValidator.java | 7 +++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 16 +++++++ .../expression/OverlapsConditionTest.java | 27 +++++++++++ 8 files changed, 116 insertions(+) create mode 100644 src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java create mode 100644 src/test/java/net/sf/jsqlparser/expression/OverlapsConditionTest.java diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java index ed4460e1c..5aa82a1d5 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java @@ -69,6 +69,8 @@ public interface ExpressionVisitor { void visit(Between between); + void visit (OverlapsCondition overlapsCondition); + void visit(EqualsTo equalsTo); void visit(GreaterThan greaterThan); diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java index 6800f325b..500103a85 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -161,6 +161,12 @@ public void visit(Between expr) { expr.getBetweenExpressionEnd().accept(this); } + public void visit(OverlapsCondition overlapsCondition) { + overlapsCondition.getLeft().accept(this); + overlapsCondition.getRight().accept(this); + } + + @Override public void visit(EqualsTo expr) { visitBinaryExpression(expr); diff --git a/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java b/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java new file mode 100644 index 000000000..f9e41b4bc --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java @@ -0,0 +1,47 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class OverlapsCondition extends ASTNodeAccessImpl implements Expression{ + + + private ExpressionList left; + private ExpressionList right; + + + public OverlapsCondition(ExpressionList left, ExpressionList right) { + this.left = left; + this.right = right; + } + + public ExpressionList getLeft() { + return left; + } + + public ExpressionList getRight() { + return right; + } + + @Override + public void accept(ExpressionVisitor expressionVisitor) { + expressionVisitor.visit(this); + } + + @Override + public String toString() { + return String.format("%s OVERLAPS %s" + , left.toString() + , right.toString() + ); + } +} diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 945b163a1..21c3f6721 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -189,6 +189,12 @@ public void visit(Between between) { between.getBetweenExpressionEnd().accept(this); } + @Override + public void visit(OverlapsCondition overlapsCondition) { + overlapsCondition.getLeft().accept(this); + overlapsCondition.getRight().accept(this); + } + @Override public void visit(Column tableColumn) { if (allowColumnProcessing && tableColumn.getTable() != null && tableColumn.getTable().getName() != null) { diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index 5b33fab0c..166e079d2 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -107,6 +107,11 @@ public void visit(Between between) { } + @Override + public void visit(OverlapsCondition overlapsCondition) { + buffer.append(overlapsCondition.toString()); + } + @Override public void visit(EqualsTo equalsTo) { visitOldOracleJoinBinaryExpression(equalsTo, " = "); diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java index d517c4b00..3d40b9cd5 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java @@ -79,6 +79,13 @@ public void visit(Between between) { between.getBetweenExpressionEnd().accept(this); } + @Override + public void visit(OverlapsCondition overlapsCondition) { + validateOptionalExpressionList(overlapsCondition.getLeft()); + validateOptionalExpressionList(overlapsCondition.getRight()); + } + + @Override public void visit(EqualsTo equalsTo) { visitOldOracleJoinBinaryExpression(equalsTo, " = "); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index ba9a6cde8..453124707 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -320,6 +320,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -3307,6 +3308,20 @@ Expression Condition(): { return not?new NotExpression(result, exclamationMarkNot):result; } } +Expression OverlapsCondition():{ + ExpressionList left = new ExpressionList(); + ExpressionList right = new ExpressionList(); +} +{ + //As per the sql2003 standard, we need at least two items in the list if there is not explicit ROW prefix + //More than two expression are allowed per the sql2003 grammar. + "(" left = SimpleExpressionListAtLeastTwoItems() ")" + + "(" right = SimpleExpressionListAtLeastTwoItems() ")" + + {return new OverlapsCondition(left, right);} +} + Expression RegularCondition() #RegularCondition: { Expression result = null; @@ -3383,6 +3398,7 @@ Expression SQLCondition(): ( result=ExistsExpression() | LOOKAHEAD(InExpression()) result=InExpression() + | LOOKAHEAD(OverlapsCondition()) result=OverlapsCondition() | left = SimpleExpression() { result = left; } [ LOOKAHEAD(2) ((LOOKAHEAD(2) result=Between(left) | LOOKAHEAD(IsNullExpression()) result=IsNullExpression(left) diff --git a/src/test/java/net/sf/jsqlparser/expression/OverlapsConditionTest.java b/src/test/java/net/sf/jsqlparser/expression/OverlapsConditionTest.java new file mode 100644 index 000000000..d91de5add --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/OverlapsConditionTest.java @@ -0,0 +1,27 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +public class OverlapsConditionTest { + + @Test + public void testOverlapsCondition() throws JSQLParserException { + TestUtils.assertExpressionCanBeParsedAndDeparsed("(t1.start, t1.end) overlaps (t2.start, t2.end)", true); + + TestUtils.assertSqlCanBeParsedAndDeparsed("select * from dual where (start_one, end_one) overlaps (start_two, end_two)", true); + + TestUtils.assertSqlCanBeParsedAndDeparsed("select * from t1 left join t2 on (t1.start, t1.end) overlaps (t2.start, t2.end)", true); + + } +}