added null support to parsing
This commit is contained in:
@@ -4,6 +4,7 @@ import jef.expressions.BinaryExpression;
|
|||||||
import jef.expressions.ConstantExpression;
|
import jef.expressions.ConstantExpression;
|
||||||
import jef.expressions.Expression;
|
import jef.expressions.Expression;
|
||||||
import jef.expressions.FieldExpression;
|
import jef.expressions.FieldExpression;
|
||||||
|
import jef.expressions.NullExpression;
|
||||||
import jef.expressions.ParameterExpression;
|
import jef.expressions.ParameterExpression;
|
||||||
import jef.expressions.SelectExpression;
|
import jef.expressions.SelectExpression;
|
||||||
import jef.expressions.TableExpression;
|
import jef.expressions.TableExpression;
|
||||||
@@ -198,6 +199,8 @@ class FilterMethodVisitor extends MethodVisitor {
|
|||||||
case Opcodes.IF_ICMPLE:
|
case Opcodes.IF_ICMPLE:
|
||||||
case Opcodes.IF_ICMPGT:
|
case Opcodes.IF_ICMPGT:
|
||||||
case Opcodes.IF_ICMPLT:
|
case Opcodes.IF_ICMPLT:
|
||||||
|
case Opcodes.IFNULL:
|
||||||
|
case Opcodes.IFNONNULL:
|
||||||
handleLextLabel();
|
handleLextLabel();
|
||||||
condStack.add(new Cond(opcode, label, varStack));
|
condStack.add(new Cond(opcode, label, varStack));
|
||||||
varStack = new Stack<>();
|
varStack = new Stack<>();
|
||||||
@@ -311,19 +314,15 @@ class FilterMethodVisitor extends MethodVisitor {
|
|||||||
switch (cond.opcode) {
|
switch (cond.opcode) {
|
||||||
case Opcodes.IFEQ:
|
case Opcodes.IFEQ:
|
||||||
expr = right;
|
expr = right;
|
||||||
// expr = new Expression.TernaryExpression(right, cond.e1, cond.e2);
|
|
||||||
break;
|
break;
|
||||||
case Opcodes.IFNE:
|
case Opcodes.IFNE:
|
||||||
expr = right;
|
expr = new UnaryExpression(right, UnaryExpression.Operator.NOT);
|
||||||
|
break;
|
||||||
// expr = new Expression.TernaryExpression(right, cond.e1, cond.e2);
|
case Opcodes.IFNULL:
|
||||||
// if (expr instanceof Expression.TernaryExpression texpr
|
expr = new BinaryExpression(right, new UnaryExpression(NullExpression.INSTANCE, UnaryExpression.Operator.NOT), BinaryExpression.Operator.IS);
|
||||||
// && texpr.getWhenFalse() == Expression.ConstantExpression.I0) {
|
break;
|
||||||
// expr = new Expression.BinaryExpression(texpr.getCond(), texpr.getWhenTrue(), "AND");
|
case Opcodes.IFNONNULL:
|
||||||
// }
|
expr = new BinaryExpression(right, NullExpression.INSTANCE, BinaryExpression.Operator.IS);
|
||||||
// wrapInTernary = false;
|
|
||||||
|
|
||||||
expr = new UnaryExpression(expr, UnaryExpression.Operator.NOT);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
@@ -430,7 +429,9 @@ class FilterMethodVisitor extends MethodVisitor {
|
|||||||
183, "INVOKESPECIAL",
|
183, "INVOKESPECIAL",
|
||||||
184, "INVOKESTATIC",
|
184, "INVOKESTATIC",
|
||||||
185, "INVOKEINTERFACE",
|
185, "INVOKEINTERFACE",
|
||||||
186, "INVOKEDYNAMIC"
|
186, "INVOKEDYNAMIC",
|
||||||
|
198, "IFNULL",
|
||||||
|
199, "IFNONNULL"
|
||||||
);
|
);
|
||||||
|
|
||||||
private static Map<Integer, String> createOpsMap(Object... o) {
|
private static Map<Integer, String> createOpsMap(Object... o) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ public class BinaryExpression implements Expression {
|
|||||||
// OR("OR"),
|
// OR("OR"),
|
||||||
// AND("AND"),
|
// AND("AND"),
|
||||||
IN("IN"),
|
IN("IN"),
|
||||||
|
IS("IS"),
|
||||||
;
|
;
|
||||||
private final String string;
|
private final String string;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public interface Expression {
|
|||||||
BINARY,
|
BINARY,
|
||||||
CONSTANT,
|
CONSTANT,
|
||||||
FIELD,
|
FIELD,
|
||||||
|
NULL,
|
||||||
OR,
|
OR,
|
||||||
PARAMETER,
|
PARAMETER,
|
||||||
SELECT,
|
SELECT,
|
||||||
|
|||||||
19
src/main/java/jef/expressions/NullExpression.java
Normal file
19
src/main/java/jef/expressions/NullExpression.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package jef.expressions;
|
||||||
|
|
||||||
|
public class NullExpression extends ConstantExpression {
|
||||||
|
public static final NullExpression INSTANCE = new NullExpression();
|
||||||
|
|
||||||
|
private NullExpression() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return Type.NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "NULL";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package jef.expressions;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@@ -28,7 +29,7 @@ public class ParameterExpression extends ConstantExpression implements Expressio
|
|||||||
} else if (this.value == null) {
|
} else if (this.value == null) {
|
||||||
return "null";
|
return "null";
|
||||||
} else if (this.value instanceof Collection) {
|
} else if (this.value instanceof Collection) {
|
||||||
return "(" + ((Collection) this.value).stream().map(Object::toString).collect(Collectors.joining(",")) + ")";
|
return "(" + ((Collection<?>) this.value).stream().map(Objects::toString).collect(Collectors.joining(",")) + ")";
|
||||||
}
|
}
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,12 @@ public class UnaryExpression implements Expression {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
if (expr instanceof ConstantExpression) {
|
||||||
|
return operator + " " + expr;
|
||||||
|
} else {
|
||||||
return operator + " (" + expr + ")";
|
return operator + " (" + expr + ")";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum Operator {
|
public enum Operator {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import jef.expressions.BinaryExpression;
|
|||||||
import jef.expressions.ConstantExpression;
|
import jef.expressions.ConstantExpression;
|
||||||
import jef.expressions.Expression;
|
import jef.expressions.Expression;
|
||||||
import jef.expressions.FieldExpression;
|
import jef.expressions.FieldExpression;
|
||||||
|
import jef.expressions.NullExpression;
|
||||||
import jef.expressions.OrExpression;
|
import jef.expressions.OrExpression;
|
||||||
import jef.expressions.ParameterExpression;
|
import jef.expressions.ParameterExpression;
|
||||||
import jef.expressions.SelectExpression;
|
import jef.expressions.SelectExpression;
|
||||||
@@ -24,6 +25,7 @@ public abstract class ExpressionModifier {
|
|||||||
case BINARY -> modifyBinary((BinaryExpression) expr);
|
case BINARY -> modifyBinary((BinaryExpression) expr);
|
||||||
case CONSTANT -> modifyConstant((ConstantExpression) expr);
|
case CONSTANT -> modifyConstant((ConstantExpression) expr);
|
||||||
case FIELD -> modifyField((FieldExpression) expr);
|
case FIELD -> modifyField((FieldExpression) expr);
|
||||||
|
case NULL -> modifyNull((NullExpression) expr);
|
||||||
case OR -> modifyOr((OrExpression) expr);
|
case OR -> modifyOr((OrExpression) expr);
|
||||||
case PARAMETER -> modifyParameter((ParameterExpression) expr);
|
case PARAMETER -> modifyParameter((ParameterExpression) expr);
|
||||||
case SELECT -> modifySelect((SelectExpression) expr);
|
case SELECT -> modifySelect((SelectExpression) expr);
|
||||||
@@ -55,6 +57,10 @@ public abstract class ExpressionModifier {
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Expression modifyNull(NullExpression expr) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
public Expression modifyOr(OrExpression expr) {
|
public Expression modifyOr(OrExpression expr) {
|
||||||
var exprs = new ArrayList<Expression>(expr.getExprs().size());
|
var exprs = new ArrayList<Expression>(expr.getExprs().size());
|
||||||
for (Expression e : expr.getExprs()) {
|
for (Expression e : expr.getExprs()) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import jef.expressions.AndExpression;
|
|||||||
import jef.expressions.BinaryExpression;
|
import jef.expressions.BinaryExpression;
|
||||||
import jef.expressions.ConstantExpression;
|
import jef.expressions.ConstantExpression;
|
||||||
import jef.expressions.FieldExpression;
|
import jef.expressions.FieldExpression;
|
||||||
|
import jef.expressions.NullExpression;
|
||||||
import jef.expressions.OrExpression;
|
import jef.expressions.OrExpression;
|
||||||
import jef.expressions.ParameterExpression;
|
import jef.expressions.ParameterExpression;
|
||||||
import jef.expressions.SelectExpression;
|
import jef.expressions.SelectExpression;
|
||||||
@@ -50,6 +51,11 @@ public class DebugExpressionVisitor extends ExpressionVisitor {
|
|||||||
System.out.println(i() + expr.getName());
|
System.out.println(i() + expr.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitNull(NullExpression expr) {
|
||||||
|
System.out.println(i() + expr.toString());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitOr(OrExpression expr) {
|
public void visitOr(OrExpression expr) {
|
||||||
for (int i = 0; i < expr.getExprs().size(); i++) {
|
for (int i = 0; i < expr.getExprs().size(); i++) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import jef.expressions.BinaryExpression;
|
|||||||
import jef.expressions.ConstantExpression;
|
import jef.expressions.ConstantExpression;
|
||||||
import jef.expressions.Expression;
|
import jef.expressions.Expression;
|
||||||
import jef.expressions.FieldExpression;
|
import jef.expressions.FieldExpression;
|
||||||
|
import jef.expressions.NullExpression;
|
||||||
import jef.expressions.OrExpression;
|
import jef.expressions.OrExpression;
|
||||||
import jef.expressions.ParameterExpression;
|
import jef.expressions.ParameterExpression;
|
||||||
import jef.expressions.SelectExpression;
|
import jef.expressions.SelectExpression;
|
||||||
@@ -20,6 +21,7 @@ public abstract class ExpressionVisitor {
|
|||||||
case BINARY -> visitBinary((BinaryExpression) expr);
|
case BINARY -> visitBinary((BinaryExpression) expr);
|
||||||
case CONSTANT -> visitConstant((ConstantExpression) expr);
|
case CONSTANT -> visitConstant((ConstantExpression) expr);
|
||||||
case FIELD -> visitField((FieldExpression) expr);
|
case FIELD -> visitField((FieldExpression) expr);
|
||||||
|
case NULL -> visitNull((NullExpression) expr);
|
||||||
case OR -> visitOr((OrExpression) expr);
|
case OR -> visitOr((OrExpression) expr);
|
||||||
case PARAMETER -> visitParameter((ParameterExpression) expr);
|
case PARAMETER -> visitParameter((ParameterExpression) expr);
|
||||||
case SELECT -> visitSelect((SelectExpression) expr);
|
case SELECT -> visitSelect((SelectExpression) expr);
|
||||||
@@ -48,6 +50,9 @@ public abstract class ExpressionVisitor {
|
|||||||
public void visitField(FieldExpression expr) {
|
public void visitField(FieldExpression expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void visitNull(NullExpression expr) {
|
||||||
|
}
|
||||||
|
|
||||||
public void visitOr(OrExpression expr) {
|
public void visitOr(OrExpression expr) {
|
||||||
for (Expression e : expr.getExprs()) {
|
for (Expression e : expr.getExprs()) {
|
||||||
visit(e);
|
visit(e);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.junit.jupiter.api.Assertions;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class FilterOpTest {
|
public class FilterOpTest {
|
||||||
@@ -111,6 +112,7 @@ public class FilterOpTest {
|
|||||||
.toString();
|
.toString();
|
||||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a WHERE a.b = 1337 OR a.b = 420 OR a.b IN (1,3)", act);
|
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a WHERE a.b = 1337 OR a.b = 420 OR a.b IN (1,3)", act);
|
||||||
|
|
||||||
|
|
||||||
act = new DBSet<TestClass>("table1")
|
act = new DBSet<TestClass>("table1")
|
||||||
.filter(e -> e.b == 1337 || s.contains(e.b) || e.b == 420)
|
.filter(e -> e.b == 1337 || s.contains(e.b) || e.b == 420)
|
||||||
.toString();
|
.toString();
|
||||||
@@ -133,6 +135,28 @@ public class FilterOpTest {
|
|||||||
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a WHERE (a.b = 1337 OR a.b = 420) AND a.b IN (1,3)", act);
|
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a WHERE (a.b = 1337 OR a.b = 420) AND a.b IN (1,3)", act);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObject() {
|
||||||
|
String act;
|
||||||
|
var s = Arrays.asList(null, new Object());
|
||||||
|
act = new DBSet<TestClass>("table1")
|
||||||
|
.filter(e -> e.o == null)
|
||||||
|
.toString();
|
||||||
|
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a WHERE a.o IS NULL", act);
|
||||||
|
|
||||||
|
|
||||||
|
act = new DBSet<TestClass>("table1")
|
||||||
|
.filter(e -> e.o != null)
|
||||||
|
.toString();
|
||||||
|
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a WHERE a.o IS NOT NULL", act);
|
||||||
|
|
||||||
|
|
||||||
|
act = new DBSet<TestClass>("table1")
|
||||||
|
.filter(e -> e.o != null || s.contains(e.o))
|
||||||
|
.toString();
|
||||||
|
Assertions.assertEquals("SELECT * FROM (SELECT * FROM `table1`) a WHERE a.o IS NOT NULL OR a.o IN (NULL)", act);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
|
|
||||||
@@ -140,5 +164,6 @@ public class FilterOpTest {
|
|||||||
|
|
||||||
public static class TestClass implements Serializable {
|
public static class TestClass implements Serializable {
|
||||||
public int b = 1;
|
public int b = 1;
|
||||||
|
public Object o = new Object();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user