You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/12/07 14:50:14 UTC
[groovy] branch master updated: Tweak the optimizer of GINQ further
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new f27c001 Tweak the optimizer of GINQ further
f27c001 is described below
commit f27c001ebcfa5b7099c1076f4da2812dc91422be
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Dec 7 22:49:52 2020 +0800
Tweak the optimizer of GINQ further
---
.../apache/groovy/ginq/dsl/GinqAstOptimizer.groovy | 61 ++++++++++-----
.../test/org/apache/groovy/ginq/GinqTest.groovy | 90 +++++++++++++++++++++-
2 files changed, 131 insertions(+), 20 deletions(-)
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/dsl/GinqAstOptimizer.groovy b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/dsl/GinqAstOptimizer.groovy
index c892388..90f9f6b 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/dsl/GinqAstOptimizer.groovy
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/dsl/GinqAstOptimizer.groovy
@@ -27,6 +27,7 @@ import org.apache.groovy.ginq.dsl.expression.SelectExpression
import org.apache.groovy.ginq.dsl.expression.WhereExpression
import org.codehaus.groovy.ast.expr.ArgumentListExpression
import org.codehaus.groovy.ast.expr.BinaryExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
import org.codehaus.groovy.ast.expr.Expression
import org.codehaus.groovy.ast.expr.ExpressionTransformer
import org.codehaus.groovy.ast.expr.ListExpression
@@ -107,28 +108,43 @@ class GinqAstOptimizer extends GinqAstBaseVisitor {
WhereExpression whereExpression = ginqExpression.whereExpression
if (whereExpression) {
- Map<String, List<Expression>> conditionsToOptimize = [:]
- List<Expression> candidatesToOptimize = findCandidatesToOptimize(whereExpression)
+ transformFromClause(whereExpression, optimizingAliasList, allAliasList, optimizingDataSourceExpressionList)
+ transformWhereClause(whereExpression, ginqExpression)
+ }
- candidatesToOptimize.stream()
- .forEach(e -> collectConditionsToOptimize(e, allAliasList, optimizingAliasList, conditionsToOptimize))
+ return null
+ }
- transformFromClause(conditionsToOptimize, optimizingAliasList, optimizingDataSourceExpressionList)
+ private void transformWhereClause(WhereExpression whereExpression, GinqExpression ginqExpression) {
+ List<Expression> candidates = findCandidatesToOptimize(whereExpression)
+ List<Expression> nonOptimizedCandidates = candidates.grep { Expression e ->
+ if (e instanceof ConstantExpression && e.value) {
+ return false
+ }
- List<Expression> candidates = findCandidatesToOptimize(whereExpression)
- List<Expression> nonOptimizedCandidates = candidates.grep { Expression e ->
- Boolean optimize = e.getNodeMetaData(TO_OPTIMIZE)
- return null == optimize || !optimize
+ if (e instanceof BinaryExpression && e.leftExpression instanceof ConstantExpression && e.rightExpression instanceof ConstantExpression) {
+ try {
+ def result = new GroovyShell().evaluate("$e.leftExpression.text $e.operation.text $e.rightExpression.text")
+ if (result) {
+ return false
+ }
+ } catch (ignored) {
+ }
}
- if (nonOptimizedCandidates) {
- whereExpression.filterExpr = contructFilterExpr(nonOptimizedCandidates)
- } else {
- ginqExpression.whereExpression = null
+ Boolean optimize = e.getNodeMetaData(TO_OPTIMIZE)
+ if (null == optimize || !optimize) {
+ return true
}
+
+ return false
}
- return null
+ if (nonOptimizedCandidates) {
+ whereExpression.filterExpr = constructFilterExpr(nonOptimizedCandidates)
+ } else {
+ ginqExpression.whereExpression = null
+ }
}
private List<Expression> findCandidatesToOptimize(WhereExpression whereExpression) {
@@ -166,14 +182,20 @@ class GinqAstOptimizer extends GinqAstBaseVisitor {
return candidatesToOptimize
}
static boolean isCandidate(Expression expression) {
- if (expression instanceof BinaryExpression && expression.operation.type in [Types.LOGICAL_AND, Types.LOGICAL_OR]) {
+ if (expression instanceof BinaryExpression && expression.operation.type in LOGICAL_OP_TYPE_LIST) {
return false
}
return true
}
- private void transformFromClause(LinkedHashMap<String, List<Expression>> conditionsToOptimize, List<String> optimizingAliasList, List<DataSourceExpression> optimizingDataSourceExpressionList) {
+ private void transformFromClause(WhereExpression whereExpression, List<String> optimizingAliasList, List<String> allAliasList, List<DataSourceExpression> optimizingDataSourceExpressionList) {
+ Map<String, List<Expression>> conditionsToOptimize = [:]
+ List<Expression> candidatesToOptimize = findCandidatesToOptimize(whereExpression)
+
+ candidatesToOptimize.stream()
+ .forEach(e -> collectConditionsToOptimize(e, allAliasList, optimizingAliasList, conditionsToOptimize))
+
conditionsToOptimize.forEach((String alias, List<Expression> conditions) -> {
if (!optimizingAliasList.contains(alias)) return
@@ -192,7 +214,7 @@ class GinqAstOptimizer extends GinqAstBaseVisitor {
contructedGinqExpression.fromExpression =
new FromExpression(new VariableExpression(constructedAlias), dataSourceExpression.dataSourceExpr)
contructedGinqExpression.whereExpression =
- new WhereExpression(contructFilterExpr(transformedConditions))
+ new WhereExpression(constructFilterExpr(transformedConditions))
contructedGinqExpression.selectExpression =
new SelectExpression(
new ArgumentListExpression(
@@ -219,7 +241,7 @@ class GinqAstOptimizer extends GinqAstBaseVisitor {
})).getExpression(0)
}
- private Expression contructFilterExpr(List<Expression> conditions) {
+ private Expression constructFilterExpr(List<Expression> conditions) {
if (!conditions) throw new IllegalArgumentException("The argument `conditions` should not be empty")
if (1 == conditions.size()) return conditions[0]
@@ -228,7 +250,7 @@ class GinqAstOptimizer extends GinqAstBaseVisitor {
}
def condition = conditions[0]
- def remainingCondition = contructFilterExpr(conditions[1..-1])
+ def remainingCondition = constructFilterExpr(conditions[1..-1])
return new BinaryExpression(condition, new Token(Types.LOGICAL_AND, '&&', -1, -1), remainingCondition)
}
@@ -264,5 +286,6 @@ class GinqAstOptimizer extends GinqAstBaseVisitor {
}
}
+ private static final List<Integer> LOGICAL_OP_TYPE_LIST = [Types.LOGICAL_AND, Types.LOGICAL_OR]
private static final String TO_OPTIMIZE = "TO_OPTIMIZE"
}
diff --git a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
index 010b37b..0ad87f7 100644
--- a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
+++ b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
@@ -3485,6 +3485,94 @@ class GinqTest {
def hello() {
def c = {
from n1 in nums1
+ innerjoin n2 in nums2 on n1 == n2
+ where n1 > 1 && n2 <= 3 && true
+ select n1, n2
+ }
+ return
+ }
+ '''
+ def sourceUnit
+ def ast = new CompilationUnit().tap {
+ sourceUnit = addSource 'hello.groovy', code
+ compile Phases.CONVERSION
+ }.ast
+
+ MethodNode methodNode = ast.classes[0].methods.grep(e -> e.name == 'hello')[0]
+ ExpressionStatement delcareStatement = ((BlockStatement) methodNode.getCode()).getStatements()[0]
+ DeclarationExpression declarationExpression = delcareStatement.getExpression()
+ ClosureExpression closureException = declarationExpression.rightExpression
+
+ GinqAstBuilder ginqAstBuilder = new GinqAstBuilder(sourceUnit)
+ closureException.code.visit(ginqAstBuilder)
+ GinqExpression ginqExpression = ginqAstBuilder.getGinqExpression()
+
+ GinqAstOptimizer ginqAstOptimizer = new GinqAstOptimizer()
+ ginqAstOptimizer.visitGinqExpression(ginqExpression)
+ assert null == ginqExpression.whereExpression
+
+ assert ginqExpression.fromExpression.dataSourceExpr instanceof GinqExpression
+ BinaryExpression contructedFilterExpr1 = ((GinqExpression) ginqExpression.fromExpression.dataSourceExpr).whereExpression.filterExpr
+ assert Types.COMPARE_GREATER_THAN == contructedFilterExpr1.operation.type
+ assert '1' == contructedFilterExpr1.rightExpression.text
+
+ assert ginqExpression.joinExpressionList[0].dataSourceExpr instanceof GinqExpression
+ BinaryExpression contructedFilterExpr2 = ((GinqExpression) ginqExpression.joinExpressionList[0].dataSourceExpr).whereExpression.filterExpr
+ assert Types.COMPARE_LESS_THAN_EQUAL == contructedFilterExpr2.operation.type
+ assert '3' == contructedFilterExpr2.rightExpression.text
+ }
+
+ @Test
+ @CompileDynamic
+ void "testGinq - optimize - 3"() {
+ def code = '''
+ def hello() {
+ def c = {
+ from n1 in nums1
+ innerjoin n2 in nums2 on n1 == n2
+ where n1 > 1 && n2 <= 3 && 1 < 2 && 3 == 3 && 4 > 3
+ select n1, n2
+ }
+ return
+ }
+ '''
+ def sourceUnit
+ def ast = new CompilationUnit().tap {
+ sourceUnit = addSource 'hello.groovy', code
+ compile Phases.CONVERSION
+ }.ast
+
+ MethodNode methodNode = ast.classes[0].methods.grep(e -> e.name == 'hello')[0]
+ ExpressionStatement delcareStatement = ((BlockStatement) methodNode.getCode()).getStatements()[0]
+ DeclarationExpression declarationExpression = delcareStatement.getExpression()
+ ClosureExpression closureException = declarationExpression.rightExpression
+
+ GinqAstBuilder ginqAstBuilder = new GinqAstBuilder(sourceUnit)
+ closureException.code.visit(ginqAstBuilder)
+ GinqExpression ginqExpression = ginqAstBuilder.getGinqExpression()
+
+ GinqAstOptimizer ginqAstOptimizer = new GinqAstOptimizer()
+ ginqAstOptimizer.visitGinqExpression(ginqExpression)
+ assert null == ginqExpression.whereExpression
+
+ assert ginqExpression.fromExpression.dataSourceExpr instanceof GinqExpression
+ BinaryExpression contructedFilterExpr1 = ((GinqExpression) ginqExpression.fromExpression.dataSourceExpr).whereExpression.filterExpr
+ assert Types.COMPARE_GREATER_THAN == contructedFilterExpr1.operation.type
+ assert '1' == contructedFilterExpr1.rightExpression.text
+
+ assert ginqExpression.joinExpressionList[0].dataSourceExpr instanceof GinqExpression
+ BinaryExpression contructedFilterExpr2 = ((GinqExpression) ginqExpression.joinExpressionList[0].dataSourceExpr).whereExpression.filterExpr
+ assert Types.COMPARE_LESS_THAN_EQUAL == contructedFilterExpr2.operation.type
+ assert '3' == contructedFilterExpr2.rightExpression.text
+ }
+
+ @Test
+ @CompileDynamic
+ void "testGinq - optimize - 4"() {
+ def code = '''
+ def hello() {
+ def c = {
+ from n1 in nums1
leftjoin n2 in nums2 on n1 == n2
where n1 > 1 && n2 <= 3
select n1, n2
@@ -3523,7 +3611,7 @@ class GinqTest {
}
@Test
- void "testGinq - optimize - 3"() {
+ void "testGinq - optimize - 5"() {
assertScript '''
// tag::ginq_optimize_01[]
assert [[2, 2]] == GQ(optimize:false) {