| /** |
| * 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.lens.cube.parse; |
| |
| import static org.apache.lens.cube.metadata.DateFactory.*; |
| |
| import static org.testng.Assert.assertEquals; |
| import static org.testng.Assert.fail; |
| |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.SortedSet; |
| import java.util.TreeSet; |
| |
| import org.apache.lens.cube.error.ConflictingFields; |
| import org.apache.lens.cube.error.FieldsCannotBeQueriedTogetherException; |
| import org.apache.lens.server.api.error.LensException; |
| |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.hive.ql.parse.ParseException; |
| |
| import org.testng.annotations.BeforeClass; |
| import org.testng.annotations.Test; |
| |
| public class FieldsCannotBeQueriedTogetherTest extends TestQueryRewrite { |
| |
| private Configuration conf = new Configuration(); |
| |
| @BeforeClass |
| public void beforeClassFieldsCannotBeQueriedTogetherTest() { |
| conf.setBoolean(CubeQueryConfUtil.ENABLE_SELECT_TO_GROUPBY, true); |
| conf.setBoolean(CubeQueryConfUtil.DISABLE_AGGREGATE_RESOLVER, false); |
| conf.setBoolean(CubeQueryConfUtil.DISABLE_AUTO_JOINS, false); |
| } |
| |
| @Test |
| public void testQueryWithDimensionAndMeasure() throws ParseException, LensException { |
| |
| /* If all the queried dimensions are present in a derived cube, and one of the queried measure is not present in |
| the same derived cube, then query shall be disallowed. |
| |
| dim2 and msr1 are not present in the same derived cube, hence query shall be disallowed with appropriate |
| exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select dim2, SUM(msr1) from basecube where " + TWO_DAYS_RANGE, |
| Arrays.asList("dim2", "d_time", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithDimensionAndMeasureInExpression() throws ParseException, LensException { |
| |
| /* If all the queried dimensions are present in a derived cube, and one of the queried measure is not present in |
| the same derived cube, then query shall be disallowed. |
| |
| dim2 and roundedmsr1 (expression over msr1) are not present in the same derived cube, hence query shall be |
| disallowed with appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select dim2, sum(roundedmsr1) from basecube where " + TWO_DAYS_RANGE, |
| Arrays.asList("dim2", "d_time", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithDimensionInExpressionAndMeasure() throws ParseException, LensException { |
| |
| /* If all the queried dimensions are present in a derived cube, and one of the queried measure is not present in |
| the same derived cube, then query shall be disallowed. |
| |
| substrexprdim2( an expresison over dim2) and msr1 are not present in the same derived cube, hence query shall be |
| disallowed with appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select substrexprdim2, SUM(msr1) from basecube where " + TWO_DAYS_RANGE, |
| Arrays.asList("dim2", "d_time", "dim2chain.name", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithDimensionAndMeasureInExpressions() throws ParseException, LensException { |
| |
| /* If all the queried dimensions are present in a derived cube, and one of the queried measure is not present in |
| the same derived cube, then query shall be disallowed. |
| |
| substrexprdim2( an expresison over dim2) and roundedmsr1 (an expression over msr1) are not present in the same |
| derived cube, hence query shall be disallowed with appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select substrexprdim2, sum(roundedmsr1) from basecube where " |
| + TWO_DAYS_RANGE, Arrays.asList("dim2", "d_time", "dim2chain.name", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithChainReferencedDimensionAttributeAndMeasure() throws ParseException, |
| LensException { |
| |
| /* In this query a dimension attribute referenced through join chain name is used in select. If the |
| source column for such a dimension attribute and the queried measure are not present in the same derived cube, |
| then query shall be disallowed. |
| |
| cityState.name is a dimension attribute used in select statement and referenced through join chain name citystate. |
| It is queryable through chain source column cityid. cityid and msr1 are not present in the same derived cube, hence |
| query shall be disallowed with appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select citystate.name, SUM(msr1) from basecube where " + TWO_DAYS_RANGE, |
| Arrays.asList("citystate.name", "d_time", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithChainReferencedDimensionAttributeAndExprMeasure() throws ParseException, |
| LensException { |
| |
| /* In this query a dimension attribute referenced through join chain name is used in select. If the |
| source column for such a dimension attribute and the queried measure are not present in the same derived cube, |
| then query shall be disallowed. |
| |
| cityState.name is a dimension attribute used in select statement and referenced through join chain name citystate. |
| It is queryable through chain source column cityid. cityid and roundedmsr1 (an expression over msr1) are not present |
| in the same derived cube, hence query shall be disallowed with appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select citystate.name, sum(roundedmsr1) from basecube where " |
| + TWO_DAYS_RANGE, Arrays.asList("citystate.name", "d_time", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithDimExprWithChainRefAndExprMeasure() throws ParseException, |
| LensException { |
| |
| /* In this query a dimension attribute referenced through join chain name is used in select. If the |
| source column for such a dimension attribute and the queried measure are not present in the same derived cube, |
| then query shall be disallowed. |
| |
| cubestate.name is a dimension attribute used in select statement and referenced through join chain name citystate. |
| It is queryable through chain source column cityid. cityid and roundedmsr1 (an expression over msr1) are not present |
| in the same derived cube, hence query shall be disallowed with appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select cubestateName, sum(roundedmsr1) from basecube where " |
| + TWO_DAYS_RANGE, Arrays.asList("cubestate.name", "d_time", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithMeasureAndChainReferencedDimAttributeInFilter() throws ParseException, |
| LensException { |
| |
| /* In this query a dimension attribute referenced through join chain name is used in filter. If the |
| source column for such a dimension attribute and the queried measure are not present in the same derived cube, |
| then query shall be disallowed. |
| |
| cityState.name is a dimension attribute used in where clause(filter) and referenced through join chain name. It is |
| queryable through chain source column cityid. cityid and msr1 are not present in the same derived cube, hence query |
| shall be disallowed with appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select SUM(msr1) from basecube where cityState.name = 'foo' and " |
| + TWO_DAYS_RANGE, Arrays.asList("citystate.name", "d_time", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithExprMeasureAndChainReferencedDimAttributeInFilter() throws ParseException, |
| LensException { |
| |
| /* In this query a dimension attribute referenced through join chain name is used in filter. If the |
| source column for such a dimension attribute and the queried measure are not present in the same derived cube, |
| then query shall be disallowed. |
| |
| cityState.name is a dimension attribute used in where clause(filter) and referenced through join chain name. It is |
| queryable through chain source column cityid. cityid and roundedmsr1( expression over msr1) are not present in the |
| same derived cube, hence query shall be disallowed with appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select sum(roundedmsr1) from basecube where cityState.name = 'foo' and " |
| + TWO_DAYS_RANGE, Arrays.asList("citystate.name", "d_time", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithExprMeasureAndDimExprWithChainRefInFilter() throws ParseException, |
| LensException { |
| |
| /* In this query a dimension attribute referenced through join chain name is used in filter. If the |
| source column for such a dimension attribute and the queried measure are not present in the same derived cube, |
| then query shall be disallowed. |
| |
| cubestate.name is a dimension attribute used in where clause(filter) and referenced through join chain name. It is |
| queryable through chain source column cityid. cityid and roundedmsr1( expression over msr1) are not present in the |
| same derived cube, hence query shall be disallowed with appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError( |
| "select sum(roundedmsr1) from basecube where cubestatename = 'foo' and " + TWO_DAYS_RANGE, |
| Arrays.asList("cubestate.name", "d_time", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWithOnlyMeasure() throws ParseException, LensException { |
| |
| /* A query which contains only measure should pass, if the measure is present in some derived cube. |
| msr1 is present in one of the derived cubes, hence query shall pass without any exception. */ |
| |
| rewrite("select SUM(msr1) from basecube where " + TWO_DAYS_RANGE, conf); |
| } |
| |
| @Test |
| public void testQueryWithOnlyExprMeasure() throws ParseException, LensException { |
| |
| /* A query which contains only measure should pass, if the measure is present in some derived cube. |
| roundedmsr1 ( an expression over msr1) is present in one of the derived cubes, hence query shall pass without |
| any exception. */ |
| |
| rewrite("select sum(roundedmsr1) from basecube where " + TWO_DAYS_RANGE, conf); |
| } |
| |
| @Test |
| public void testQueryWithMeasureAndChainReferencedDimAttributeInCaseStatement() throws ParseException, |
| LensException { |
| |
| /* In this query a dimension attribute referenced through join chain name is used in case statement. |
| A query which contains such a dim attribute and a measure is allowed even if the source column of the used dim |
| attribute and the queried measure are not present in the same derived cube. |
| |
| cityState.name is a dimension attribute used in where clause(filter) and referenced through join chain name |
| cityState. It is queryable through source column basecube.cityid. basecube.cityid and msr1 are not present in the |
| same derived cube. However since cityState.name is only present in the case statement, the query is allowed. */ |
| rewrite("select SUM(CASE WHEN cityState.name ='foo' THEN msr1 END) from basecube where " + TWO_DAYS_RANGE, conf); |
| } |
| |
| @Test |
| public void testQueryWithDimAttributesNotInSameDerviedCube() throws ParseException, LensException { |
| |
| /* dim2 and countryid are not present in the same derived cube, hence query should be disallowed */ |
| |
| testFieldsCannotBeQueriedTogetherError("select dim2, countryid, SUM(msr2) from basecube where " + TWO_DAYS_RANGE, |
| Arrays.asList("countryid", "d_time", "dim2")); |
| } |
| |
| @Test |
| public void testQueryWithDimExpressionssNotInSameDerviedCube() |
| throws ParseException, LensException { |
| |
| /* dim2, source columns of cubestate and countryid are not present in the same derived cube, hence query should be |
| * disallowed */ |
| |
| testFieldsCannotBeQueriedTogetherError("select substrexprdim2, cubeStateName, countryid, SUM(msr2) from basecube" |
| + " where " + TWO_DAYS_RANGE, |
| Arrays.asList("countryid", "dim2", "cubestate.name", "d_time", "dim2chain.name")); |
| } |
| |
| @Test |
| public void testQueryWithMeasureNotInAnyDerviedCube() throws ParseException, LensException { |
| |
| /* newmeasure is not present in any derived cube, hence the query should be disallowed. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select newmeasure from basecube where " + TWO_DAYS_RANGE, |
| Arrays.asList("d_time", "newmeasure")); |
| } |
| |
| @Test |
| public void testQueryWithExprMeasureNotInAnyDerviedCube() throws ParseException, LensException { |
| |
| /* newexpr : expression over newmeasure is not present in any derived cube, hence the query should be disallowed. */ |
| |
| testFieldsCannotBeQueriedTogetherError("select newexpr from basecube where " |
| + TWO_DAYS_RANGE, Arrays.asList("d_time", "newmeasure")); |
| } |
| |
| @Test |
| public void testQueryWithReferencedDimAttributeAndMeasure() throws ParseException, |
| LensException { |
| |
| /* In this query a referenced dimension attribute is used in select statement. If the source column for such a |
| dimension attribute and the queried measure are not present in the same derived cube, then query shall be |
| disallowed. |
| |
| cityStateCapital is a referenced dimension attribute used in select statement. It is queryable through chain source |
| column cityid. cityid and msr1 are not present in the same derived cube, hence query shall be disallowed with |
| appropriate exception. */ |
| |
| testFieldsCannotBeQueriedTogetherError( |
| "select citystatecapital, SUM(msr1) from basecube where " + TWO_DAYS_RANGE, |
| Arrays.asList("citystatecapital", "d_time", "msr1")); |
| } |
| |
| @Test |
| public void testQueryWtihTimeDimAndReplaceTimeDimSwitchTrue() throws ParseException, LensException { |
| |
| /* If a time dimension and measure are not present in the same derived cube, then query shall be disallowed. |
| |
| The testQuery in this test uses d_time in time range func. d_time is a time dimension in basecube. |
| d_time is present as a dimension in derived cube where as msr4 is not present in the same derived cube, hence |
| the query shall be disallowed. |
| |
| The testQuery in this test uses its own queryConf which has CubeQueryConfUtil.REPLACE_TIMEDIM_WITH_PART_COL |
| set to true. */ |
| |
| Configuration queryConf = new Configuration(conf); |
| queryConf.setBoolean(CubeQueryConfUtil.REPLACE_TIMEDIM_WITH_PART_COL, true); |
| |
| testFieldsCannotBeQueriedTogetherError("select msr4 from basecube where " + TWO_DAYS_RANGE, |
| Arrays.asList("d_time", "msr4"), queryConf); |
| } |
| |
| @Test |
| public void testQueryWtihTimeDimAndReplaceTimeDimSwitchFalse() throws ParseException, LensException { |
| |
| /* If a time dimension and measure are not present in the same derived cube, then query shall be disallowed. |
| |
| The testQuery in this test uses d_time in time range func. d_time is a time dimension in basecube. |
| d_time is present as a dimension in derived cube where as msr4 is not present in the same derived cube, hence |
| the query shall be disallowed. |
| |
| The testQuery in this test uses its own queryConf which has CubeQueryConfUtil.REPLACE_TIMEDIM_WITH_PART_COL |
| set to false */ |
| |
| Configuration queryConf = new Configuration(conf); |
| queryConf.setBoolean(CubeQueryConfUtil.REPLACE_TIMEDIM_WITH_PART_COL, false); |
| |
| testFieldsCannotBeQueriedTogetherError("select msr4 from basecube where " + TWO_DAYS_RANGE, |
| Arrays.asList("d_time", "msr4"), queryConf); |
| } |
| |
| private void testFieldsCannotBeQueriedTogetherError(final String testQuery, final List<String> conflictingFields) |
| throws ParseException, LensException { |
| testFieldsCannotBeQueriedTogetherError(testQuery, conflictingFields, conf); |
| } |
| |
| private void testFieldsCannotBeQueriedTogetherError(final String testQuery, final List<String> conflictingFields, |
| final Configuration queryConf) |
| throws ParseException, LensException { |
| |
| try { |
| |
| String hqlQuery = rewrite(testQuery, queryConf); |
| fail("Expected Query Rewrite to fail with FieldsCannotBeQueriedTogetherException, however it didn't happen. " |
| + "Query got re-written to:" + hqlQuery); |
| } catch(FieldsCannotBeQueriedTogetherException actualException) { |
| |
| SortedSet<String> expectedFields = new TreeSet<>(conflictingFields); |
| |
| FieldsCannotBeQueriedTogetherException expectedException = |
| new FieldsCannotBeQueriedTogetherException(new ConflictingFields(expectedFields)); |
| assertEquals(actualException, expectedException); |
| } |
| } |
| } |