forked from sqlancer/sqlancer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimplifyExpressions.java
More file actions
98 lines (82 loc) · 3.3 KB
/
SimplifyExpressions.java
File metadata and controls
98 lines (82 loc) · 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package sqlancer.transformations;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
import net.sf.jsqlparser.util.deparser.SelectDeParser;
/**
* This transformation simplifies complicated expressions e.g: a + (b + c) -> b.
*/
public class SimplifyExpressions extends JSQLParserBasedTransformation {
public SimplifyExpressions() {
super("simplify expressions. e.g. a + b -> a");
}
@Override
public boolean init(String sql) {
boolean baseSuc = super.init(sql);
if (!baseSuc) {
return false;
}
this.simplifier.setExpressionVisitor(expressionHandler);
this.expressionHandler.setSelectVisitor(simplifier);
return true;
}
private final ExpressionDeParser expressionHandler = new ExpressionDeParser() {
@Override
protected void visitBinaryExpression(BinaryExpression binaryExpression, String operator) {
Expression lhs = binaryExpression.getLeftExpression();
Expression rhs = binaryExpression.getRightExpression();
handleExpression(binaryExpression, lhs, BinaryExpression::setLeftExpression);
handleExpression(binaryExpression, rhs, BinaryExpression::setRightExpression);
super.visitBinaryExpression(binaryExpression, operator);
}
};
private final SelectDeParser simplifier = new SelectDeParser() {
@Override
public void visit(PlainSelect plainSelect) {
handleSelect(plainSelect);
super.visit(plainSelect);
}
};
@Override
public void apply() {
super.apply();
if (statement instanceof Select) {
Select select = (Select) statement;
select.getSelectBody().accept(simplifier);
}
}
private void handleSelect(PlainSelect plainSelect) {
Expression where = plainSelect.getWhere();
if (where != null) {
handleExpression(plainSelect, where, PlainSelect::setWhere);
}
Expression having = plainSelect.getHaving();
if (having != null) {
handleExpression(plainSelect, having, PlainSelect::setHaving);
}
}
private List<Expression> flattenExpression(Expression expression) {
if (expression instanceof BinaryExpression) {
BinaryExpression binaryExpression = (BinaryExpression) expression;
return List.of(binaryExpression.getLeftExpression(), binaryExpression.getRightExpression());
} else if (expression instanceof Parenthesis) {
return List.of(((Parenthesis) expression).getExpression());
}
return new ArrayList<>();
}
private <P> void handleExpression(P parent, Expression expr, BiConsumer<P, Expression> setter) {
List<Expression> expressions = flattenExpression(expr);
for (Expression variant : expressions) {
boolean suc = tryReplace(parent, expr, variant, setter);
if (suc) {
break;
}
}
}
}