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/11/29 09:48:00 UTC

[groovy] branch master updated: Validate fields of `groupby` clause

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 307bb34  Validate fields of `groupby` clause
307bb34 is described below

commit 307bb347ce395e5d02cb67f8bfe3754398a2b3cf
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Nov 29 17:47:34 2020 +0800

    Validate fields of `groupby` clause
---
 .../ginq/provider/collection/GinqAstWalker.groovy  | 62 ++++++++++++++--------
 .../test/org/apache/groovy/ginq/GinqTest.groovy    |  4 +-
 .../org/apache/groovy/ginq/GinqErrorTest.groovy    | 15 ++++++
 3 files changed, 58 insertions(+), 23 deletions(-)

diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy
index ddb17f7..e7357d0 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy
@@ -437,6 +437,20 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
         Expression projectionExpr = selectExpression.getProjectionExpr()
 
         List<Expression> expressionList = ((TupleExpression) projectionExpr).getExpressions()
+
+        if (groupByVisited) {
+            final groupNameList = groupNameListExpression.getExpressions().stream().map(e -> e.text).collect(Collectors.toList())
+            for (Expression expr : expressionList) {
+                if (!(expr instanceof MethodCallExpression || (expr instanceof CastExpression && expr.expression instanceof MethodCallExpression))
+                        && (transformCol(expr).v2.text !in groupNameList)) {
+                    this.collectSyntaxError(new GinqSyntaxError(
+                            "`${expr.text}` is not in the `groupby` clause",
+                            expr.getLineNumber(), expr.getColumnNumber()
+                    ))
+                }
+            }
+        }
+
         Expression lambdaCode = expressionList.get(0)
         def expressionListSize = expressionList.size()
         if (expressionListSize > 1 || (expressionListSize == 1 && lambdaCode instanceof CastExpression)) {
@@ -472,33 +486,39 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
         return selectMethodCallExpression
     }
 
+    private static Tuple2<Expression, Expression> transformCol(Expression e) {
+        Expression elementExpression = e
+        Expression nameExpression = null
+
+        if (e instanceof CastExpression) {
+            elementExpression = e.expression
+            nameExpression = new ConstantExpression(e.type.text)
+        } else if (e instanceof PropertyExpression) {
+            if (e.property instanceof ConstantExpression) {
+                elementExpression = e
+                nameExpression = new ConstantExpression(e.property.text)
+            } else if (e.property instanceof GStringExpression) {
+                elementExpression = e
+                nameExpression = e.property
+            }
+        }
+
+        if (null == nameExpression) {
+            nameExpression = new ConstantExpression(e.text)
+        }
+
+        return tuple(elementExpression, nameExpression)
+    }
+
     private ConstructorCallExpression constructNamedRecordCtorCallExpression(List<Expression> expressionList, String metaDataKey) {
         int expressionListSize = expressionList.size()
         List<Expression> elementExpressionList = new ArrayList<>(expressionListSize)
         List<Expression> nameExpressionList = new ArrayList<>(expressionListSize)
         for (Expression e : expressionList) {
-            Expression elementExpression = e
-            Expression nameExpression = null
-
-            if (e instanceof CastExpression) {
-                elementExpression = e.expression
-                nameExpression = new ConstantExpression(e.type.text)
-            } else if (e instanceof PropertyExpression) {
-                if (e.property instanceof ConstantExpression) {
-                    elementExpression = e
-                    nameExpression = new ConstantExpression(e.property.text)
-                } else if (e.property instanceof GStringExpression) {
-                    elementExpression = e
-                    nameExpression = e.property
-                }
-            }
-
-            if (null == nameExpression) {
-                nameExpression = new ConstantExpression(e.text)
-            }
+            Tuple2<Expression, Expression> elementAndName = transformCol(e)
 
-            elementExpressionList << elementExpression
-            nameExpressionList << nameExpression
+            elementExpressionList << elementAndName.v1
+            nameExpressionList << elementAndName.v2
         }
 
         def nameListExpression = new ListExpression(nameExpressionList)
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 7b4def3..c22070a 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
@@ -2074,9 +2074,9 @@ class GinqTest {
         assertScript '''
             def test() {
                 final int x = 1
-                assert [[1, 1, 2], [3, 1, 2], [6, 1, 3]] == GQ {
+                assert [[1, 1, 2], [6, 1, 3], [3, 1, 2]] == GQ {
                     from n in [1, 1, 3, 3, 6, 6, 6]
-                    groupby n
+                    groupby n, x
                     select n, x, count(n)
                 }.toList()
             }
diff --git a/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqErrorTest.groovy b/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqErrorTest.groovy
index 4ce1eeb..3fe0258 100644
--- a/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqErrorTest.groovy
+++ b/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqErrorTest.groovy
@@ -21,6 +21,7 @@ package org.apache.groovy.ginq
 import groovy.transform.CompileStatic
 import org.junit.Test
 
+import static groovy.test.GroovyAssert.assertScript
 import static groovy.test.GroovyAssert.shouldFail
 
 @CompileStatic
@@ -307,4 +308,18 @@ class GinqErrorTest {
 
         assert err.toString().contains('subquery returns more than one value: [3, 4]')
     }
+
+    @Test
+    void "testGinq - from groupby select - 17"() {
+        def err = shouldFail '''\
+            GQ {
+                from n in [1, 2, 3]
+                innerjoin m in [2, 3, 4] on m == n
+                groupby n
+                select n, m, count(n)
+            }.toList()    
+        '''
+
+        assert err.toString().contains('`m` is not in the `groupby` clause @ line 5, column 27.')
+    }
 }