From 44983dec478fd5ac6a470b5bde3cb8cb4769e29f Mon Sep 17 00:00:00 2001 From: shawkins Date: Tue, 14 Jan 2014 21:17:57 -0500 Subject: [PATCH] TEIID-2801 addressing hive having support and having support in general --- .../translator/hive/HiveExecutionFactory.java | 14 +++-- .../relational/rules/RuleCollapseSource.java | 51 +++++++++++++++++++ .../relational/rules/RuleRaiseAccess.java | 3 +- .../optimizer/TestAggregatePushdown.java | 26 +++++++++- 4 files changed, 84 insertions(+), 10 deletions(-) diff --git a/connectors/translator-hive/src/main/java/org/teiid/translator/hive/HiveExecutionFactory.java b/connectors/translator-hive/src/main/java/org/teiid/translator/hive/HiveExecutionFactory.java index 5bbe326d8c..1c59c09fe7 100644 --- a/connectors/translator-hive/src/main/java/org/teiid/translator/hive/HiveExecutionFactory.java +++ b/connectors/translator-hive/src/main/java/org/teiid/translator/hive/HiveExecutionFactory.java @@ -21,14 +21,7 @@ */ package org.teiid.translator.hive; -import static org.teiid.translator.TypeFacility.RUNTIME_NAMES.BIG_INTEGER; -import static org.teiid.translator.TypeFacility.RUNTIME_NAMES.DATE; -import static org.teiid.translator.TypeFacility.RUNTIME_NAMES.DOUBLE; -import static org.teiid.translator.TypeFacility.RUNTIME_NAMES.FLOAT; -import static org.teiid.translator.TypeFacility.RUNTIME_NAMES.INTEGER; -import static org.teiid.translator.TypeFacility.RUNTIME_NAMES.OBJECT; -import static org.teiid.translator.TypeFacility.RUNTIME_NAMES.STRING; -import static org.teiid.translator.TypeFacility.RUNTIME_NAMES.TIMESTAMP; +import static org.teiid.translator.TypeFacility.RUNTIME_NAMES.*; import java.sql.ResultSet; import java.sql.SQLException; @@ -388,4 +381,9 @@ protected FunctionMethod addAggregatePushDownFunction(String qualifier, String n method.setAggregateAttributes(attr); return method; } + + @Override + public boolean supportsHaving() { + return false; //only having with group by + } } diff --git a/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleCollapseSource.java b/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleCollapseSource.java index 82f7c59740..46c7563971 100644 --- a/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleCollapseSource.java +++ b/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleCollapseSource.java @@ -260,6 +260,57 @@ private QueryCommand createQuery(CommandContext context, CapabilitiesFinder capF ExpressionMappingVisitor.mapExpressions(query.getSelect(), symbolMap.asMap(), true); ExpressionMappingVisitor.mapExpressions(query.getHaving(), symbolMap.asMap(), true); + if (query.getHaving() != null && !CapabilitiesUtil.supports(Capability.QUERY_HAVING, modelID, metadata, capFinder)) { + Select sel = query.getSelect(); + GroupBy groupBy = query.getGroupBy(); + Criteria having = query.getHaving(); + query.setHaving(null); + OrderBy orderBy = query.getOrderBy(); + query.setOrderBy(null); + Limit limit = query.getLimit(); + query.setLimit(null); + Set aggs = new HashSet(); + aggs.addAll(AggregateSymbolCollectorVisitor.getAggregates(having, true)); + Set expr = new HashSet(); + for (Expression ex : sel.getProjectedSymbols()) { + Expression selectExpression = SymbolMap.getExpression(ex); + aggs.remove(selectExpression); + expr.add(selectExpression); + } + int originalSelect = sel.getSymbols().size(); + sel.addSymbols(aggs); + if (groupBy != null) { + for (Expression ex : groupBy.getSymbols()) { + ex = SymbolMap.getExpression(ex); + if (expr.add(ex)) { + sel.addSymbol(ex); + } + } + } + Query outerQuery = null; + try { + outerQuery = QueryRewriter.createInlineViewQuery(new GroupSymbol("X"), query, metadata, query.getSelect().getProjectedSymbols()); //$NON-NLS-1$ + } catch (TeiidException err) { + throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30257, err); + } + Iterator iter = outerQuery.getSelect().getProjectedSymbols().iterator(); + HashMap expressionMap = new HashMap(); + for (Expression symbol : query.getSelect().getProjectedSymbols()) { + //need to unwrap on both sides as the select expression could be aliased + //TODO: could add an option to createInlineViewQuery to disable alias creation + expressionMap.put(SymbolMap.getExpression(symbol), SymbolMap.getExpression(iter.next())); + } + ExpressionMappingVisitor.mapExpressions(having, expressionMap, true); + outerQuery.setCriteria(having); + ExpressionMappingVisitor.mapExpressions(orderBy, expressionMap, true); + outerQuery.setOrderBy(orderBy); + outerQuery.setLimit(limit); + ExpressionMappingVisitor.mapExpressions(select, expressionMap, true); + outerQuery.getSelect().setSymbols(outerQuery.getSelect().getProjectedSymbols().subList(0, originalSelect)); + outerQuery.setOption(query.getOption()); + query = outerQuery; + + } if (!CapabilitiesUtil.supports(Capability.QUERY_FUNCTIONS_IN_GROUP_BY, modelID, metadata, capFinder)) { //if group by expressions are not support, add an inline view to compensate query = RuleCollapseSource.rewriteGroupByAsView(query, metadata, false); diff --git a/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java b/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java index 15e253cc46..e4d260f68c 100644 --- a/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java +++ b/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java @@ -465,7 +465,8 @@ static boolean canRaiseOverSelect(PlanNode accessNode, return false; } - if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_HAVING) && !CapabilitiesUtil.supports(Capability.QUERY_HAVING, modelID, metadata, capFinder)) { + if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_HAVING) && !CapabilitiesUtil.supports(Capability.QUERY_HAVING, modelID, metadata, capFinder) + && !CapabilitiesUtil.supports(Capability.QUERY_FROM_INLINE_VIEWS, modelID, metadata, capFinder)) { parentNode.recordDebugAnnotation("having is not supported by source", modelID, "cannot push having", record, metadata); //$NON-NLS-1$ //$NON-NLS-2$ return false; } diff --git a/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java b/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java index e42028bdf8..744cc87d0d 100644 --- a/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java +++ b/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java @@ -1307,5 +1307,29 @@ null, new DefaultCapabilitiesFinder(bsc), ProcessorPlan plan = TestOptimizer.helpPlan("select FIRST_VALUE(e1) OVER (ORDER BY e2) from pm1.g2", metadata, null, capFinder, //$NON-NLS-1$ new String[]{"SELECT FIRST_VALUE(ALL g_0.e1) OVER (ORDER BY g_0.e2) FROM pm1.g2 AS g_0"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ TestOptimizer.checkNodeTypes(plan, TestOptimizer.FULL_PUSHDOWN); - } + } + + @Test public void testHavingPushdown() throws Exception { + FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder(); + BasicSourceCapabilities caps = getAggregateCapabilities(); + caps.setCapabilitySupport(Capability.QUERY_HAVING, false); + capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$ + + ProcessorPlan plan = TestOptimizer.helpPlan("select max(e2) from pm1.g2 having min(e2) > 1", RealMetadataFactory.example1Cached(), null, capFinder, //$NON-NLS-1$ + new String[]{"SELECT v_0.c_0 FROM (SELECT MAX(g_0.e2) AS c_0, MIN(g_0.e2) AS c_1 FROM pm1.g2 AS g_0) AS v_0 WHERE v_0.c_1 > 1"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ + TestOptimizer.checkNodeTypes(plan, TestOptimizer.FULL_PUSHDOWN); + } + + @Test public void testHavingPushdown1() throws Exception { + FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder(); + BasicSourceCapabilities caps = getAggregateCapabilities(); + caps.setCapabilitySupport(Capability.QUERY_HAVING, false); + caps.setFunctionSupport("concat", true); + caps.setFunctionSupport("convert", true); + capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$ + + ProcessorPlan plan = TestOptimizer.helpPlan("select max(e2) from pm1.g2 group by e1 having min(e2) || e1 > '1'", RealMetadataFactory.example1Cached(), null, capFinder, //$NON-NLS-1$ + new String[]{"SELECT v_0.c_0 FROM (SELECT MAX(g_0.e2) AS c_0, MIN(g_0.e2) AS c_1, g_0.e1 AS c_2 FROM pm1.g2 AS g_0 GROUP BY g_0.e1) AS v_0 WHERE concat(convert(v_0.c_1, string), v_0.c_2) > '1'"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ + TestOptimizer.checkNodeTypes(plan, TestOptimizer.FULL_PUSHDOWN); + } }