Repository: drill Updated Branches: refs/heads/master 6796006f2 -> 453f6f7a8 DRILL-3196: Disable multiple partitions in a SELECT-CLAUSE Project: http://git-wip-us.apache.org/repos/asf/drill/repo Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/453f6f7a Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/453f6f7a Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/453f6f7a Branch: refs/heads/master Commit: 453f6f7a8328658563b7704d1400a882857d104b Parents: 6796006 Author: Hsuan-Yi Chu Authored: Mon Jun 1 11:09:16 2015 -0700 Committer: Aman Sinha Committed: Thu Jun 11 09:52:54 2015 -0700 ---------------------------------------------------------------------- .../sql/parser/UnsupportedOperatorsVisitor.java | 65 ++++++++++--- .../apache/drill/exec/TestWindowFunctions.java | 98 ++++++++++++++++++++ 2 files changed, 152 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/drill/blob/453f6f7a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/UnsupportedOperatorsVisitor.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/UnsupportedOperatorsVisitor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/UnsupportedOperatorsVisitor.java index f1ec851..b92de3b 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/UnsupportedOperatorsVisitor.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/UnsupportedOperatorsVisitor.java @@ -17,12 +17,15 @@ */ package org.apache.drill.exec.planner.sql.parser; -import org.apache.calcite.sql.SqlSelect; -import org.apache.calcite.sql.fun.SqlCountAggFunction; import org.apache.drill.exec.ExecConstants; import org.apache.drill.exec.exception.UnsupportedOperatorCollector; import org.apache.drill.exec.ops.QueryContext; import org.apache.drill.exec.work.foreman.SqlUnsupportedException; + +import org.apache.calcite.sql.SqlIdentifier; +import org.apache.calcite.sql.SqlSelect; +import org.apache.calcite.sql.SqlWindow; +import org.apache.calcite.sql.fun.SqlCountAggFunction; import org.apache.calcite.sql.SqlCall; import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.SqlJoin; @@ -32,7 +35,9 @@ import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.sql.util.SqlShuttle; import org.apache.calcite.sql.SqlDataTypeSpec; import org.apache.calcite.sql.SqlSetOperator; + import java.util.List; + import com.google.common.collect.Lists; public class UnsupportedOperatorsVisitor extends SqlShuttle { @@ -78,6 +83,53 @@ public class UnsupportedOperatorsVisitor extends SqlShuttle { @Override public SqlNode visit(SqlCall sqlCall) { + // Inspect the window functions + if(sqlCall instanceof SqlSelect) { + SqlSelect sqlSelect = (SqlSelect) sqlCall; + + // This is used to keep track of the window function which has been defined + SqlNode definedWindow = null; + for(SqlNode nodeInSelectList : sqlSelect.getSelectList()) { + if(nodeInSelectList.getKind() == SqlKind.OVER) { + // Throw exceptions if window functions are disabled + if(!context.getOptions().getOption(ExecConstants.ENABLE_WINDOW_FUNCTIONS).bool_val) { + unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, + "Window functions are disabled\n" + + "See Apache Drill JIRA: DRILL-2559"); + throw new UnsupportedOperationException(); + } + + SqlNode window = ((SqlCall) nodeInSelectList).operand(1); + + // Partition window is referenced as a SqlIdentifier, + // which is defined in the window list + if(window instanceof SqlIdentifier) { + // Expand the SqlIdentifier as the expression defined in the window list + for(SqlNode sqlNode : sqlSelect.getWindowList()) { + if(((SqlWindow) sqlNode).getDeclName().equalsDeep(window, false)) { + window = sqlNode; + break; + } + } + + assert !(window instanceof SqlIdentifier) : "Identifier should have been expanded as a window defined in the window list"; + } + + // In a SELECT-SCOPE, only a partition can be defined + if(definedWindow == null) { + definedWindow = window; + } else { + if(!definedWindow.equalsDeep(window, false)) { + unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, + "Multiple window definitions in a single SELECT list is not currently supported \n" + + "See Apache Drill JIRA: DRILL-3196"); + throw new UnsupportedOperationException(); + } + } + } + } + } + // Disable unsupported Intersect, Except if(sqlCall.getKind() == SqlKind.INTERSECT || sqlCall.getKind() == SqlKind.EXCEPT) { unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.RELATIONAL, @@ -118,15 +170,6 @@ public class UnsupportedOperatorsVisitor extends SqlShuttle { } } - // Throw exceptions if window functions are disabled - if(sqlCall.getOperator().getKind().equals(SqlKind.OVER) - && !context.getOptions().getOption(ExecConstants.ENABLE_WINDOW_FUNCTIONS).bool_val) { - unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, - "Window functions are disabled\n" + - "See Apache Drill JIRA: DRILL-2559"); - throw new UnsupportedOperationException(); - } - // Disable Function for(String strOperator : disabledOperators) { if(sqlCall.getOperator().isName(strOperator)) { http://git-wip-us.apache.org/repos/asf/drill/blob/453f6f7a/exec/java-exec/src/test/java/org/apache/drill/exec/TestWindowFunctions.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/TestWindowFunctions.java b/exec/java-exec/src/test/java/org/apache/drill/exec/TestWindowFunctions.java new file mode 100644 index 0000000..fc75d73 --- /dev/null +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/TestWindowFunctions.java @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.drill.exec; + +import org.apache.drill.BaseTestQuery; +import org.apache.drill.common.exceptions.UserException; +import org.apache.drill.exec.work.foreman.SqlUnsupportedException; +import org.apache.drill.exec.work.foreman.UnsupportedFunctionException; +import org.junit.Test; + +public class TestWindowFunctions extends BaseTestQuery { + private static void throwAsUnsupportedException(UserException ex) throws Exception { + SqlUnsupportedException.errorClassNameToException(ex.getOrCreatePBError(false).getException().getExceptionClass()); + throw ex; + } + + @Test // DRILL-3196 + public void testSinglePartition() throws Exception { + final String query = "explain plan for select sum(a2) over(partition by a2), count(*) over(partition by a2) \n" + + "from cp.`tpch/nation.parquet`"; + + test("alter session set `window.enable` = true"); + test(query); + test("alter session set `window.enable` = false"); + } + + @Test // DRILL-3196 + public void testSinglePartitionDefinedInWindowList() throws Exception { + final String query = "explain plan for select sum(a2) over w \n" + + "from cp.`tpch/nation.parquet` \n" + + "window w as (partition by a2 order by a2)"; + + test("alter session set `window.enable` = true"); + test(query); + test("alter session set `window.enable` = false"); + } + + @Test(expected = UnsupportedFunctionException.class) // DRILL-3196 + public void testMultiplePartitions() throws Exception { + try { + final String query = "explain plan for select sum(a2) over(partition by a2), count(*) over(partition by a2,b2,c2) \n" + + "from cp.`tpch/nation.parquet`"; + + test("alter session set `window.enable` = true"); + test(query); + test("alter session set `window.enable` = false"); + } catch(UserException ex) { + throwAsUnsupportedException(ex); + throw ex; + } + } + + @Test(expected = UnsupportedFunctionException.class) // DRILL-3196 + public void testSinglePartitionMultipleOrderBy() throws Exception { + try { + final String query = "explain plan for select sum(a2) over(partition by a2 order by a2), count(*) over(partition by a2 order by b2) \n" + + "from cp.`tpch/nation.parquet`"; + + test("alter session set `window.enable` = true"); + test(query); + test("alter session set `window.enable` = false"); + } catch(UserException ex) { + throwAsUnsupportedException(ex); + throw ex; + } + } + + @Test(expected = UnsupportedFunctionException.class) // DRILL-3196 + public void testMultiplePartitionsDefinedInWindowList() throws Exception { + try { + final String query = "explain plan for select sum(a2) over(partition by a2), count(*) over w \n" + + "from cp.`tpch/nation.parquet` \n" + + "window w as (partition by a2, b2, c2)"; + + test("alter session set `window.enable` = true"); + test(query); + test("alter session set `window.enable` = false"); + } catch(UserException ex) { + throwAsUnsupportedException(ex); + throw ex; + } + } +}