Author: shawkins
Date: 2011-10-28 16:43:18 -0400 (Fri, 28 Oct 2011)
New Revision: 3594
Added:
trunk/engine/src/test/java/org/teiid/query/processor/TestFunctionPushdown.java
Modified:
trunk/engine/src/main/java/org/teiid/query/analysis/AnalysisRecord.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleConstants.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/NestedTableJoinStrategy.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java
trunk/engine/src/main/resources/org/teiid/query/i18n.properties
trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
trunk/engine/src/test/java/org/teiid/query/optimizer/relational/TestRuleStack.java
Log:
TEIID-964 adding support for pushing must pushdown functions in the select clause
Modified: trunk/engine/src/main/java/org/teiid/query/analysis/AnalysisRecord.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/analysis/AnalysisRecord.java 2011-10-27
19:31:00 UTC (rev 3593)
+++ trunk/engine/src/main/java/org/teiid/query/analysis/AnalysisRecord.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -23,7 +23,6 @@
package org.teiid.query.analysis;
import java.io.PrintWriter;
-import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
@@ -209,7 +208,7 @@
* @param projectedSymbols The list of SingleElementSymbol projected from a plan or
node
* @return List of output columns for sending to the client as part of the plan
*/
- public static List<String>
getOutputColumnProperties(List<SingleElementSymbol> projectedSymbols) {
+ public static List<String> getOutputColumnProperties(List<? extends
SingleElementSymbol> projectedSymbols) {
if(projectedSymbols != null) {
List<String> outputCols = new
ArrayList<String>(projectedSymbols.size());
for(int i=0; i<projectedSymbols.size() ; i++) {
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java 2011-10-27
19:31:00 UTC (rev 3593)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -64,6 +64,7 @@
import org.teiid.query.optimizer.relational.plantree.NodeConstants.Info;
import org.teiid.query.optimizer.relational.rules.CapabilitiesUtil;
import org.teiid.query.optimizer.relational.rules.CriteriaCapabilityValidatorVisitor;
+import org.teiid.query.optimizer.relational.rules.RuleAssignOutputElements;
import org.teiid.query.optimizer.relational.rules.RuleCollapseSource;
import org.teiid.query.optimizer.relational.rules.RuleConstants;
import org.teiid.query.optimizer.relational.rules.RuleMergeCriteria;
@@ -406,7 +407,7 @@
rules.push(RuleConstants.CALCULATE_COST);
- rules.push(RuleConstants.ASSIGN_OUTPUT_ELEMENTS);
+ rules.push(new RuleAssignOutputElements(true));
if (hints.hasLimit) {
rules.push(RuleConstants.PUSH_LIMIT);
@@ -454,7 +455,7 @@
}
if (hints.hasVirtualGroups || (hints.hasJoin && hints.hasOptionalJoin))
{
//do initial filtering to make merging and optional join logic easier
- rules.push(RuleConstants.ASSIGN_OUTPUT_ELEMENTS);
+ rules.push(new RuleAssignOutputElements(false));
}
rules.push(RuleConstants.PLACE_ACCESS);
return rules;
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java 2011-10-27
19:31:00 UTC (rev 3593)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -35,6 +35,8 @@
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.core.TeiidComponentException;
+import org.teiid.metadata.FunctionMethod.PushDown;
+import org.teiid.query.QueryPlugin;
import org.teiid.query.analysis.AnalysisRecord;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
@@ -58,12 +60,16 @@
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.ExpressionSymbol;
+import org.teiid.query.sql.symbol.Function;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.sql.symbol.WindowFunction;
import org.teiid.query.sql.util.SymbolMap;
import org.teiid.query.sql.visitor.AggregateSymbolCollectorVisitor;
import org.teiid.query.sql.visitor.ElementCollectorVisitor;
+import org.teiid.query.sql.visitor.EvaluatableVisitor;
+import org.teiid.query.sql.visitor.ExpressionMappingVisitor;
+import org.teiid.query.sql.visitor.FunctionCollectorVisitor;
import org.teiid.query.sql.visitor.GroupsUsedByElementsVisitor;
import org.teiid.query.util.CommandContext;
@@ -76,6 +82,13 @@
* from the children nodes. </p>
*/
public final class RuleAssignOutputElements implements OptimizerRule {
+
+ private boolean finalRun;
+ private boolean checkSymbols;
+
+ public RuleAssignOutputElements(boolean finalRun) {
+ this.finalRun = finalRun;
+ }
/**
* Execute the rule. This rule is executed exactly once during every planning
@@ -141,6 +154,13 @@
if (command instanceof StoredProcedure) {
//if the access node represents a stored procedure, then we can't
actually change the output symbols
root.setProperty(NodeConstants.Info.OUTPUT_COLS,
command.getProjectedSymbols());
+ } else if (checkSymbols) {
+ Object modelId = RuleRaiseAccess.getModelIDFromAccess(root, metadata);
+ for (SingleElementSymbol symbol : outputElements) {
+ if(!RuleRaiseAccess.canPushSymbol(symbol, true, modelId, metadata,
capFinder, analysisRecord)) {
+ throw new
QueryPlannerException(QueryPlugin.Util.getString("RuleAssignOutputElements.couldnt_push_expression",
symbol, modelId)); //$NON-NLS-1$
+ }
+ }
}
case NodeConstants.Types.TUPLE_LIMIT:
case NodeConstants.Types.DUP_REMOVE:
@@ -195,7 +215,7 @@
PlanNode sortNode = NodeEditor.findParent(root, NodeConstants.Types.SORT,
NodeConstants.Types.SOURCE);
if (sortNode != null &&
sortNode.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT)) {
//if this is the initial rule run, remove unrelated order before changing
the project cols
- if (rules.contains(RuleConstants.ASSIGN_OUTPUT_ELEMENTS)) {
+ if (!finalRun) {
OrderBy elements = (OrderBy)
sortNode.getProperty(NodeConstants.Info.SORT_ORDER);
projectCols = new ArrayList<SingleElementSymbol>(projectCols);
for (OrderByItem item : elements.getOrderByItems()) {
@@ -298,16 +318,21 @@
* virtual elements - so just reset it and proceed as before
* @throws TeiidComponentException
* @throws QueryMetadataException
+ * @throws QueryPlannerException
*/
static List<? extends SingleElementSymbol> determineSourceOutput(PlanNode
root,
List<SingleElementSymbol>
outputElements,
QueryMetadataInterface metadata,
- CapabilitiesFinder capFinder) throws
QueryMetadataException, TeiidComponentException {
+ CapabilitiesFinder capFinder) throws
QueryMetadataException, TeiidComponentException, QueryPlannerException {
PlanNode virtualRoot = root.getLastChild();
if(hasDupRemoval(virtualRoot)) {
// Reset the outputColumns for this source node to be all columns for the
virtual group
SymbolMap symbolMap = (SymbolMap)
root.getProperty(NodeConstants.Info.SYMBOL_MAP);
+ if (!symbolMap.asMap().keySet().containsAll(outputElements)) {
+ outputElements.removeAll(symbolMap.asMap().keySet());
+ throw new
QueryPlannerException(QueryPlugin.Util.getString("RuleAssignOutputElements.cannot_introduce_expressions",
outputElements)); //$NON-NLS-1$
+ }
return symbolMap.getKeys();
}
PlanNode limit = NodeEditor.findNodePreOrder(root,
NodeConstants.Types.TUPLE_LIMIT, NodeConstants.Types.PROJECT);
@@ -359,8 +384,9 @@
* @param sourceNode Node to filter
* @param metadata Metadata implementation
* @return The filtered list of columns for this node (used in recursing tree)
+ * @throws QueryPlannerException
*/
- static List<SingleElementSymbol> filterVirtualElements(PlanNode sourceNode,
List<SingleElementSymbol> outputColumns, QueryMetadataInterface metadata) {
+ static List<SingleElementSymbol> filterVirtualElements(PlanNode sourceNode,
List<SingleElementSymbol> outputColumns, QueryMetadataInterface metadata) throws
QueryPlannerException {
PlanNode virtualRoot = sourceNode.getLastChild();
@@ -379,10 +405,16 @@
boolean updateGroups = outputColumns.size() != originalOrder.size();
boolean[] seenIndex = new boolean[outputColumns.size()];
+ boolean newSymbols = false;
for (int i = 0; i < outputColumns.size(); i++) {
Expression expr = outputColumns.get(i);
filteredIndex[i] = originalOrder.indexOf(expr);
+ if (filteredIndex[i] == -1) {
+ updateGroups = true;
+ //we're adding this symbol, which needs to be updated against respective
symbol maps
+ newSymbols = true;
+ }
if (!updateGroups) {
seenIndex[filteredIndex[i]] = true;
}
@@ -402,8 +434,21 @@
PlanNode projectNode = allProjects.get(i);
List<SingleElementSymbol> projectCols =
(List<SingleElementSymbol>)
projectNode.getProperty(NodeConstants.Info.PROJECT_COLS);
- newCols = RelationalNode.projectTuple(filteredIndex, projectCols);
+ newCols = RelationalNode.projectTuple(filteredIndex, projectCols, true);
+ if (newSymbols) {
+ SymbolMap childMap = SymbolMap.createSymbolMap(symbolMap.getKeys(), (List)
projectNode.getProperty(NodeConstants.Info.PROJECT_COLS));
+ for (int j = 0; j < filteredIndex.length; j++) {
+ if (filteredIndex[j] != -1) {
+ continue;
+ }
+ SingleElementSymbol ex = (SingleElementSymbol) outputColumns.get(j).clone();
+ ExpressionMappingVisitor.mapExpressions(ex, childMap.asMap());
+ newCols.set(j, ex);
+ filteredIndex[j] = j;
+ }
+ }
+
projectNode.setProperty(NodeConstants.Info.PROJECT_COLS, newCols);
if (updateGroups) {
projectNode.getGroups().clear();
@@ -428,25 +473,6 @@
for (int i = 0; i < filteredIndex.length; i++) {
newMap.addMapping(originalOrder.get(filteredIndex[i]),
originalExpressionOrder.get(filteredIndex[i]));
}
- PlanNode sortNode = NodeEditor.findNodePreOrder(sourceNode,
NodeConstants.Types.SORT, NodeConstants.Types.PROJECT);
- if (sortNode != null) {
- OrderBy elements = (OrderBy)
sortNode.getProperty(NodeConstants.Info.SORT_ORDER);
- for (OrderByItem item : elements.getOrderByItems()) {
- if (item.getExpressionPosition() == -1) {
- continue;
- }
- item.setExpressionPosition(-1);
- for (int i = 0; i < filteredIndex.length; i++) {
- if (item.getExpressionPosition() == filteredIndex[i]) {
- item.setExpressionPosition(i);
- break;
- }
- }
- if (item.getExpressionPosition() == -1) {
- sortNode.setProperty(NodeConstants.Info.UNRELATED_SORT, true);
- }
- }
- }
sourceNode.setProperty(NodeConstants.Info.SYMBOL_MAP, newMap);
}
@@ -501,7 +527,23 @@
if (ss instanceof WindowFunction || (ss instanceof ExpressionSymbol
&& !(ss instanceof AggregateSymbol))) {
createdSymbols.add(ss);
}
- ElementCollectorVisitor.getElements(ss, requiredSymbols);
+ boolean symbolRequired = false;
+ if (finalRun && !(ss instanceof ElementSymbol) &&
NodeEditor.findParent(node, NodeConstants.Types.ACCESS) == null) {
+ Collection<Function> functions =
FunctionCollectorVisitor.getFunctions(ss, false);
+ for (Function function : functions) {
+ if (function.getFunctionDescriptor().getPushdown() != PushDown.MUST_PUSHDOWN ||
EvaluatableVisitor.willBecomeConstant(function)) {
+ continue;
+ }
+ //assume we need the whole thing
+ requiredSymbols.add(ss);
+ symbolRequired = true;
+ checkSymbols = true;
+ break;
+ }
+ }
+ if (!symbolRequired) {
+ ElementCollectorVisitor.getElements(ss, requiredSymbols);
+ }
}
break;
}
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleConstants.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleConstants.java 2011-10-27
19:31:00 UTC (rev 3593)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleConstants.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -36,7 +36,6 @@
public static final OptimizerRule RAISE_ACCESS = new RuleRaiseAccess();
public static final OptimizerRule CHOOSE_DEPENDENT = new RuleChooseDependent();
public static final OptimizerRule COLLAPSE_SOURCE = new RuleCollapseSource();
- public static final OptimizerRule ASSIGN_OUTPUT_ELEMENTS = new
RuleAssignOutputElements();
public static final OptimizerRule COPY_CRITERIA = new RuleCopyCriteria();
public static final OptimizerRule CLEAN_CRITERIA = new RuleCleanCriteria();
public static final OptimizerRule VALIDATE_WHERE_ALL = new RuleValidateWhereAll();
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java 2011-10-27
19:31:00 UTC (rev 3593)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -202,11 +202,12 @@
* Removes source layers that only do a simple projection of the elements below.
* @throws TeiidComponentException
* @throws QueryMetadataException
+ * @throws QueryPlannerException
*/
private static PlanNode checkForSimpleProjection(PlanNode frame,
PlanNode root,
PlanNode parentProject,
- QueryMetadataInterface metadata)
throws QueryMetadataException, TeiidComponentException {
+ QueryMetadataInterface metadata)
throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
// check that the parent only performs projection
PlanNode nodeToCheck = parentProject.getFirstChild();
while (nodeToCheck != frame) {
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java 2011-10-27
19:31:00 UTC (rev 3593)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -452,7 +452,7 @@
* @throws QueryMetadataException
* @since 4.1.2
*/
- private static boolean canPushSymbol(Expression symbol, boolean inSelectClause,
Object modelID,
+ static boolean canPushSymbol(Expression symbol, boolean inSelectClause, Object
modelID,
QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord
record)
throws TeiidComponentException, QueryMetadataException {
Modified:
trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java 2011-10-27
19:31:00 UTC (rev 3593)
+++
trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -167,7 +167,7 @@
}
// Incoming elements and lookup map for evaluating expressions
- List<SingleElementSymbol> sourceElements =
this.getChildren()[0].getElements();
+ List<? extends SingleElementSymbol> sourceElements =
this.getChildren()[0].getElements();
this.elementMap = createLookupMap(sourceElements);
// List should contain all grouping columns / expressions as we need those for
sorting
Modified:
trunk/engine/src/main/java/org/teiid/query/processor/relational/NestedTableJoinStrategy.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/processor/relational/NestedTableJoinStrategy.java 2011-10-27
19:31:00 UTC (rev 3593)
+++
trunk/engine/src/main/java/org/teiid/query/processor/relational/NestedTableJoinStrategy.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -164,7 +164,7 @@
}
private void updateContext(List<?> tuple,
- List<SingleElementSymbol> elements) {
+ List<? extends SingleElementSymbol> elements) {
for (int i = 0; i < elements.size(); i++) {
SingleElementSymbol element = elements.get(i);
if (element instanceof ElementSymbol) {
Modified:
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java 2011-10-27
19:31:00 UTC (rev 3593)
+++
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -46,6 +46,7 @@
import org.teiid.query.processor.BatchCollector.BatchProducer;
import org.teiid.query.sql.symbol.AliasSymbol;
import org.teiid.query.sql.symbol.Expression;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.util.CommandContext;
@@ -53,7 +54,7 @@
static class NodeData {
int nodeID;
- List elements;
+ List<? extends SingleElementSymbol> elements;
Number estimateNodeCardinality;
Number setSizeEstimate;
Number depAccessEstimate;
@@ -165,16 +166,16 @@
}
}
- public void setElements(List elements) {
+ public void setElements(List<? extends SingleElementSymbol> elements) {
this.data.elements = elements;
}
@Override
- public List getOutputElements() {
+ public List<? extends SingleElementSymbol> getOutputElements() {
return getElements();
}
- public List getElements() {
+ public List<? extends SingleElementSymbol> getElements() {
return this.data.elements;
}
@@ -373,13 +374,21 @@
return result;
}
-
+
public static <T> List<T> projectTuple(int[] indexes, List<T>
tupleValues) {
+ return projectTuple(indexes, tupleValues, false);
+ }
+ public static <T> List<T> projectTuple(int[] indexes, List<T>
tupleValues, boolean omitMissing) {
+
List<T> projectedTuple = new ArrayList<T>(indexes.length);
for (int index : indexes) {
- projectedTuple.add(tupleValues.get(index));
+ if (omitMissing && index == -1) {
+ projectedTuple.add(null);
+ } else {
+ projectedTuple.add(tupleValues.get(index));
+ }
}
return projectedTuple;
Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2011-10-27 19:31:00
UTC (rev 3593)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2011-10-28 20:43:18
UTC (rev 3594)
@@ -941,4 +941,7 @@
DdlPlan.event_already_exists={0} already has an INSTEAD OF trigger defined for {1}.
error_refresh=error occurred during refreshing the materialized view entries for view
{0}
-support_required=Without required support property {0}, pushdown will not be enabled for
{1} on translator {2}.
\ No newline at end of file
+support_required=Without required support property {0}, pushdown will not be enabled for
{1} on translator {2}.
+
+RuleAssignOutputElements.couldnt_push_expression=Expression(s) {0} cannot be pushed to
source.
+RuleAssignOutputElements.cannot_introduce_expressions=Cannot introduce new expressions
{1} in duplicate removal.
\ No newline at end of file
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java 2011-10-27
19:31:00 UTC (rev 3593)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -6471,77 +6471,9 @@
/**
* Test the query optimizer's ability to properly plan and optimize a query
- * that uses ambiguous alias names in the top level query and its sub-query.
- * <p>
- * No source table is being used. For example, <code>SELECT A.e2 FROM
- * (SELECT e2 FROM (SELECT 1 AS e2) AS A) AS A</code>
- * <p>
- * The test is to ensure that A.e2 from the top level is not confused with
- * e2 in the second level.
- * <p>
- * Related Defects: JBEDSP-1137
- */
- @Test public void testAmbiguousAliasInSubQueryNoSource() {
- // Create query
- String sql = "SELECT A.e2 AS e2 FROM (" + //$NON-NLS-1$
- " SELECT e2 AS e2 FROM (" + //$NON-NLS-1$
- " SELECT 5 AS e2" + //$NON-NLS-1$
- " ) AS A" + //$NON-NLS-1$
- ") AS A"; //$NON-NLS-1$
-
- helpPlan(sql, RealMetadataFactory.example1Cached(), new String[] {});
- }
-
- /**
- * Test the query optimizer's ability to properly plan and optimize a query
* that uses ambiguous alias names in the top level query and its sub-query
* and uses columns belonging to the alias as a parameter to a function.
* <p>
- * No source table is being used. For example, <code>SELECT CONVERT(A.e2,
- * biginteger) AS e2 FROM (SELECT CONVERT(e2, long) AS e2 FROM (SELECT 1 AS
- * e2) AS A) AS A</code>
- * <p>
- * The test is to ensure that A.e2 from the top level is not confused with
- * e2 in the second level.
- * <p>
- * Related Defects: JBEDSP-1137
- */
- @Test public void testAmbiguousAliasFunctionInSubQueryNoSource() {
- // Create query
- String sql = "SELECT CONVERT(A.e2, biginteger) AS e2 FROM (" +
//$NON-NLS-1$
- " SELECT CONVERT(e2, long) AS e2 FROM (" + //$NON-NLS-1$
- " SELECT 5 AS e2" + //$NON-NLS-1$
- " ) AS A" + //$NON-NLS-1$
- ") AS A"; //$NON-NLS-1$
-
- helpPlan(sql, RealMetadataFactory.example1Cached(), new String[] {});
- }
-
- /**
- * Test the query optimizer's ability to properly plan and optimize a query
- * that uses ambiguous alias names in the top level query and its sub-query.
- * <p>
- * For example, <code>SELECT A.e2 FROM (SELECT e12FROM pm1.g1 AS A) AS
A</code>
- * <p>
- * The test is to ensure that A.e2 from the top level is not confused with
- * e2 in the second level.
- * <p>
- * Related Defects: JBEDSP-1137
- */
- @Test public void testAmbiguousAliasInSubQuerySource() {
- // Create query
- String sql = "SELECT A.e2 AS e2 FROM (" + //$NON-NLS-1$
- " SELECT e2 AS e2 FROM pm1.g1 AS A" + //$NON-NLS-1$
- ") AS A"; //$NON-NLS-1$
-
- helpPlan(sql, RealMetadataFactory.example1Cached(), new String[] {"SELECT e2
FROM pm1.g1 AS A"}); //$NON-NLS-1$
- }
-
- /**
- * Test the query optimizer's ability to properly plan and optimize a query
- * that uses ambiguous alias names in the top level query and its sub-query
- * and uses columns belonging to the alias as a parameter to a function.
- * <p>
* For example, <code>SELECT CONVERT(A.e2, biginteger) AS e2 FROM (SELECT
* CONVERT(e2, long) AS e2 FROM pm1.g1 AS A) AS A</code>
* <p>
Modified:
trunk/engine/src/test/java/org/teiid/query/optimizer/relational/TestRuleStack.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/optimizer/relational/TestRuleStack.java 2011-10-27
19:31:00 UTC (rev 3593)
+++
trunk/engine/src/test/java/org/teiid/query/optimizer/relational/TestRuleStack.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -22,14 +22,12 @@
package org.teiid.query.optimizer.relational;
-import org.teiid.query.optimizer.relational.OptimizerRule;
-import org.teiid.query.optimizer.relational.RuleStack;
+import junit.framework.TestCase;
+
import org.teiid.query.optimizer.relational.rules.RuleConstants;
import org.teiid.query.optimizer.relational.rules.RulePushSelectCriteria;
-import junit.framework.TestCase;
-
/**
*/
public class TestRuleStack extends TestCase {
@@ -76,12 +74,12 @@
public void testRemove() {
// Set up
RuleStack stack = new RuleStack();
- stack.push(RuleConstants.ASSIGN_OUTPUT_ELEMENTS);
+ stack.push(RuleConstants.ACCESS_PATTERN_VALIDATION);
stack.push(RuleConstants.COLLAPSE_SOURCE);
- stack.push(RuleConstants.ASSIGN_OUTPUT_ELEMENTS);
+ stack.push(RuleConstants.ACCESS_PATTERN_VALIDATION);
// Remove all instances of ASSIGN_OUTPUT_ELEMENTS
- stack.remove(RuleConstants.ASSIGN_OUTPUT_ELEMENTS);
+ stack.remove(RuleConstants.ACCESS_PATTERN_VALIDATION);
// Verify size and pop'ed values
assertEquals(1, stack.size());
@@ -92,10 +90,10 @@
public void testContains() {
// Set up
RuleStack stack = new RuleStack();
- stack.push(RuleConstants.ASSIGN_OUTPUT_ELEMENTS);
+ stack.push(RuleConstants.ACCESS_PATTERN_VALIDATION);
stack.push(RuleConstants.COLLAPSE_SOURCE);
- assertEquals(true, stack.contains(RuleConstants.ASSIGN_OUTPUT_ELEMENTS));
+ assertEquals(true, stack.contains(RuleConstants.ACCESS_PATTERN_VALIDATION));
assertEquals(false, stack.contains(RuleConstants.PLACE_ACCESS));
}
Added: trunk/engine/src/test/java/org/teiid/query/processor/TestFunctionPushdown.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestFunctionPushdown.java
(rev 0)
+++
trunk/engine/src/test/java/org/teiid/query/processor/TestFunctionPushdown.java 2011-10-28
20:43:18 UTC (rev 3594)
@@ -0,0 +1,114 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.query.processor;
+
+import static org.teiid.query.optimizer.TestOptimizer.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+import org.teiid.query.function.FunctionTree;
+import org.teiid.query.metadata.QueryMetadataInterface;
+import org.teiid.query.optimizer.FakeFunctionMetadataSource;
+import org.teiid.query.optimizer.TestOptimizer;
+import org.teiid.query.optimizer.TestOptimizer.ComparisonMode;
+import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
+import org.teiid.query.optimizer.capabilities.FakeCapabilitiesFinder;
+import org.teiid.query.unittest.RealMetadataFactory;
+
+@SuppressWarnings({"nls", "unchecked"})
+public class TestFunctionPushdown {
+
+ @Test public void testMustPushdownOverMultipleSourcesWithoutSupport() throws Exception
{
+ QueryMetadataInterface metadata =
RealMetadataFactory.createTransformationMetadata(RealMetadataFactory.example1Cached().getMetadataStore(),
"example1", new FunctionTree("foo", new
FakeFunctionMetadataSource()));
+
+ FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+ BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
+ capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+ capFinder.addCapabilities("pm2", caps); //$NON-NLS-1$
+
+ String sql = "select func(x.e1) from pm1.g1 as x, pm2.g1 as y where x.e2 =
y.e2"; //$NON-NLS-1$
+
+ helpPlan(sql, metadata, null, capFinder,
+ new String[] {}, ComparisonMode.FAILED_PLANNING);
//$NON-NLS-1$
+ }
+
+ @Test public void testMustPushdownOverMultipleSources() throws Exception {
+ QueryMetadataInterface metadata =
RealMetadataFactory.createTransformationMetadata(RealMetadataFactory.example1Cached().getMetadataStore(),
"example1", new FunctionTree("foo", new
FakeFunctionMetadataSource()));
+
+ FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+ BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
+ caps.setFunctionSupport("misc.namespace.func", true);
+ capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+ capFinder.addCapabilities("pm2", caps); //$NON-NLS-1$
+
+ String sql = "select func(x.e1) from pm1.g1 as x, pm2.g1 as y where x.e2 =
y.e2"; //$NON-NLS-1$
+
+ ProcessorPlan plan = helpPlan(sql, metadata, null, capFinder,
+ new String[] {"SELECT g_0.e2 AS c_0,
func(g_0.e1) AS c_1 FROM pm1.g1 AS g_0 ORDER BY c_0", "SELECT g_0.e2 AS c_0 FROM
pm2.g1 AS g_0 ORDER BY c_0"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+
+ HardcodedDataManager dataManager = new HardcodedDataManager();
+ dataManager.addData("SELECT g_0.e2 AS c_0, func(g_0.e1) AS c_1 FROM pm1.g1
AS g_0 ORDER BY c_0", new List[] {Arrays.asList(1, "a")});
+ dataManager.addData("SELECT g_0.e2 AS c_0 FROM pm2.g1 AS g_0 ORDER BY
c_0", new List[] {Arrays.asList(1), Arrays.asList(2)});
+
+ TestProcessor.helpProcess(plan, dataManager, new List[]
{Arrays.asList("a")});
+ }
+
+ @Test public void testMustPushdownOverMultipleSourcesWithView() throws Exception {
+ QueryMetadataInterface metadata =
RealMetadataFactory.createTransformationMetadata(RealMetadataFactory.example1Cached().getMetadataStore(),
"example1", new FunctionTree("foo", new
FakeFunctionMetadataSource()));
+
+ FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+ BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
+ caps.setFunctionSupport("misc.namespace.func", true);
+ capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+ capFinder.addCapabilities("pm2", caps); //$NON-NLS-1$
+
+ String sql = "select func(x.e1) from (select x.* from pm1.g1 as x, pm2.g1 as
y where x.e2 = y.e2 order by e1 limit 10) as x"; //$NON-NLS-1$
+
+ ProcessorPlan plan = helpPlan(sql, metadata, null, capFinder,
+ new String[] {"SELECT g_0.e2 AS c_0 FROM
pm2.g1 AS g_0 ORDER BY c_0", "SELECT g_0.e2 AS c_0, func(g_0.e1) AS c_1, g_0.e1
AS c_2 FROM pm1.g1 AS g_0 ORDER BY c_0"}, ComparisonMode.EXACT_COMMAND_STRING);
//$NON-NLS-1$
+
+ HardcodedDataManager dataManager = new HardcodedDataManager();
+ dataManager.addData("SELECT g_0.e2 AS c_0 FROM pm2.g1 AS g_0 ORDER BY
c_0", new List[] {Arrays.asList(1)});
+ dataManager.addData("SELECT g_0.e2 AS c_0, func(g_0.e1) AS c_1, g_0.e1 AS
c_2 FROM pm1.g1 AS g_0 ORDER BY c_0", new List[] {Arrays.asList(1, "aa",
"a"), Arrays.asList(2, "bb", "b")});
+
+ TestProcessor.helpProcess(plan, dataManager, new List[]
{Arrays.asList("aa")});
+ }
+
+ @Test public void testMustPushdownOverMultipleSourcesWithViewDupRemoval() throws
Exception {
+ QueryMetadataInterface metadata =
RealMetadataFactory.createTransformationMetadata(RealMetadataFactory.example1Cached().getMetadataStore(),
"example1", new FunctionTree("foo", new
FakeFunctionMetadataSource()));
+
+ FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+ BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
+ caps.setFunctionSupport("misc.namespace.func", true);
+ capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+ capFinder.addCapabilities("pm2", caps); //$NON-NLS-1$
+
+ String sql = "select func(x.e1) from (select distinct x.* from pm1.g1 as x,
pm2.g1 as y where x.e2 = y.e2 order by e1 limit 10) as x"; //$NON-NLS-1$
+
+ helpPlan(sql, metadata, null, capFinder,
+ new String[] {}, ComparisonMode.FAILED_PLANNING);
//$NON-NLS-1$
+ }
+
+}
Property changes on:
trunk/engine/src/test/java/org/teiid/query/processor/TestFunctionPushdown.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain