Author: shawkins
Date: 2012-05-21 11:54:43 -0400 (Mon, 21 May 2012)
New Revision: 4130
Modified:
trunk/client/src/main/java/org/teiid/client/plan/Annotation.java
trunk/engine/src/main/java/org/teiid/query/analysis/AnalysisRecord.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
trunk/engine/src/main/java/org/teiid/query/optimizer/xml/XMLQueryPlanner.java
trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java
trunk/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java
Log:
TEIID-2043 condensing plan size and also converting many debug statements to annotations
Modified: trunk/client/src/main/java/org/teiid/client/plan/Annotation.java
===================================================================
--- trunk/client/src/main/java/org/teiid/client/plan/Annotation.java 2012-05-21 15:16:44
UTC (rev 4129)
+++ trunk/client/src/main/java/org/teiid/client/plan/Annotation.java 2012-05-21 15:54:43
UTC (rev 4130)
@@ -35,6 +35,7 @@
public static final String MATERIALIZED_VIEW = "Materialized View";
//$NON-NLS-1$
public static final String CACHED_PROCEDURE = "Cached Procedure";
//$NON-NLS-1$
public static final String HINTS = "Hints"; //$NON-NLS-1$
+ public static final String RELATIONAL_PLANNER = "Relational Planner";
//$NON-NLS-1$
public enum Priority {
LOW,
Modified: trunk/engine/src/main/java/org/teiid/query/analysis/AnalysisRecord.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/analysis/AnalysisRecord.java 2012-05-21
15:16:44 UTC (rev 4129)
+++ trunk/engine/src/main/java/org/teiid/query/analysis/AnalysisRecord.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -32,6 +32,7 @@
import org.teiid.client.plan.Annotation;
import org.teiid.client.plan.PlanNode;
+import org.teiid.client.plan.Annotation.Priority;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.util.PropertiesUtils;
import org.teiid.logging.LogConstants;
@@ -159,6 +160,10 @@
return this.recordDebug;
}
+ public void addAnnotation(String category, String annotation, String resolution,
Priority priority) {
+ addAnnotation(new Annotation(category, annotation, resolution, priority));
+ }
+
/**
* Add an annotation. This can only be used if {@link #recordAnnotations}
* returns true.
@@ -166,6 +171,9 @@
*/
public void addAnnotation(Annotation annotation) {
this.annotations.add(annotation);
+ if (this.recordDebug()) {
+ this.println(annotation.getPriority() + " " + annotation.getCategory()
+ " " + annotation.getAnnotation() + " - " +
annotation.getResolution()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
}
/**
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -22,19 +22,14 @@
package org.teiid.query.optimizer.relational.plantree;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
+import org.teiid.api.exception.query.QueryMetadataException;
+import org.teiid.client.plan.Annotation;
+import org.teiid.client.plan.Annotation.Priority;
+import org.teiid.core.TeiidComponentException;
+import org.teiid.query.analysis.AnalysisRecord;
+import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.sql.LanguageObject;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.SubqueryContainer;
@@ -54,6 +49,8 @@
/** The type of node, as defined by NodeConstants.Types. */
private int type;
+
+ private boolean modified;
/** The parent of this node, null if root. */
private PlanNode parent;
@@ -98,6 +95,7 @@
if (this.parent != null) {
this.parent.children.remove(this);
}
+ this.modified = true;
this.parent = parent;
}
@@ -112,6 +110,7 @@
childIter.remove();
child.parent = null;
}
+ this.modified = true;
return childrenCopy;
}
@@ -134,11 +133,13 @@
}
public void addFirstChild(PlanNode child) {
+ this.modified = true;
this.children.addFirst(child);
child.setParent(this);
}
public void addLastChild(PlanNode child) {
+ this.modified = true;
this.children.addLast(child);
child.setParent(this);
}
@@ -150,6 +151,7 @@
}
public PlanNode removeFromParent() {
+ this.modified = true;
PlanNode result = this.parent;
if (result != null) {
result.removeChild(this);
@@ -161,6 +163,7 @@
boolean result = this.children.remove(child);
if (result) {
child.parent = null;
+ modified = true;
}
return result;
}
@@ -169,13 +172,18 @@
if(nodeProperties == null) {
return null;
}
- return nodeProperties.get(propertyID);
+ Object result = nodeProperties.get(propertyID);
+ if (result != null) {
+ modified = true;
+ }
+ return result;
}
public Object setProperty(NodeConstants.Info propertyID, Object value) {
if(nodeProperties == null) {
nodeProperties = new LinkedHashMap<NodeConstants.Info, Object>();
}
+ modified = true;
return nodeProperties.put(propertyID, value);
}
@@ -183,6 +191,7 @@
if(nodeProperties == null) {
return null;
}
+ modified = true;
return nodeProperties.remove(propertyID);
}
@@ -210,10 +219,12 @@
}
public void addGroup(GroupSymbol groupID) {
+ modified = true;
groups.add(groupID);
}
public void addGroups(Collection<GroupSymbol> newGroups) {
+ modified = true;
this.groups.addAll(newGroups);
}
@@ -230,7 +241,7 @@
* @return String representing this node and all children under this node
*/
public String toString() {
- StringBuffer str = new StringBuffer();
+ StringBuilder str = new StringBuilder();
getRecursiveString(str, 0);
return str.toString();
}
@@ -240,7 +251,7 @@
* @return String representing just this node
*/
public String nodeToString() {
- StringBuffer str = new StringBuffer();
+ StringBuilder str = new StringBuilder();
getNodeString(str);
return str.toString();
}
@@ -248,13 +259,13 @@
// Define a single tab
private static final String TAB = " "; //$NON-NLS-1$
- private void setTab(StringBuffer str, int tabStop) {
+ private void setTab(StringBuilder str, int tabStop) {
for(int i=0; i<tabStop; i++) {
str.append(TAB);
}
}
- void getRecursiveString(StringBuffer str, int tabLevel) {
+ void getRecursiveString(StringBuilder str, int tabLevel) {
setTab(str, tabLevel);
getNodeString(str);
str.append(")\n"); //$NON-NLS-1$
@@ -265,13 +276,20 @@
}
}
- void getNodeString(StringBuffer str) {
+ void getNodeString(StringBuilder str) {
str.append(NodeConstants.getNodeTypeString(this.type));
str.append("(groups="); //$NON-NLS-1$
str.append(this.groups);
- if(nodeProperties != null) {
- str.append(", props="); //$NON-NLS-1$
- str.append(nodeProperties);
+ if (modified) {
+ if(nodeProperties != null) {
+ str.append(", props="); //$NON-NLS-1$
+ String props = nodeProperties.toString();
+ if (props.length() > 100000) {
+ props = props.substring(0, 100000) + "..."; //$NON-NLS-1$
+ }
+ str.append(props);
+ }
+ modified = false;
}
}
@@ -280,6 +298,7 @@
}
public void replaceChild(PlanNode child, PlanNode replacement) {
+ modified = true;
int i = this.children.indexOf(child);
this.children.set(i, replacement);
child.setParent(null);
@@ -292,6 +311,7 @@
* @param node
*/
public void addAsParent(PlanNode node) {
+ modified = true;
if (this.parent != null) {
this.parent.replaceChild(this, node);
}
@@ -395,5 +415,14 @@
}
return cardinality;
}
+
+ public void recordDebugAnnotation(String annotation, Object modelID, String resolution,
AnalysisRecord record, QueryMetadataInterface metadata) throws QueryMetadataException,
TeiidComponentException {
+ if (record != null && record.recordAnnotations()) {
+ boolean current = this.modified;
+ this.modified = true;
+ record.addAnnotation(Annotation.RELATIONAL_PLANNER, annotation + (modelID !=
null?" " + metadata.getModelID(modelID):""), resolution + "
" + this.nodeToString(), Priority.LOW); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ this.modified = current;
+ }
+ }
}
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -27,6 +27,8 @@
import java.util.HashSet;
import org.teiid.api.exception.query.QueryMetadataException;
+import org.teiid.client.plan.Annotation;
+import org.teiid.client.plan.Annotation.Priority;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.metadata.FunctionMethod.PushDown;
@@ -649,9 +651,9 @@
private void markInvalid(LanguageObject object, String reason) {
this.valid = false;
setAbort(true);
- if (analysisRecord != null && analysisRecord.recordDebug()) {
+ if (analysisRecord != null && analysisRecord.recordAnnotations()) {
try {
- analysisRecord.println(reason + " " + this.metadata.getName(this.modelID) +
": " + object); //$NON-NLS-1$ //$NON-NLS-2$
+ analysisRecord.addAnnotation(Annotation.RELATIONAL_PLANNER, reason + "
" + this.metadata.getName(this.modelID), object + " was not pushed",
Priority.LOW); //$NON-NLS-1$ //$NON-NLS-2$
} catch (QueryMetadataException e) {
} catch (TeiidComponentException e) {
}
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -130,8 +130,10 @@
* @param metadata Metadata implementation
* @param node Root node to search
* @param matches Collection to accumulate matches in
+ * @throws TeiidComponentException
+ * @throws QueryMetadataException
*/
- List<CandidateJoin> findCandidate(PlanNode root, QueryMetadataInterface
metadata, AnalysisRecord analysisRecord) {
+ List<CandidateJoin> findCandidate(PlanNode root, QueryMetadataInterface
metadata, AnalysisRecord analysisRecord) throws QueryMetadataException,
TeiidComponentException {
List<CandidateJoin> candidates = new ArrayList<CandidateJoin>();
@@ -170,53 +172,45 @@
* @param sourceNode The access node being considered
* @param analysisRecord TODO
* @return True if valid for making dependent
+ * @throws TeiidComponentException
+ * @throws QueryMetadataException
*/
- boolean isValidJoin(PlanNode joinNode, PlanNode sourceNode, AnalysisRecord
analysisRecord) {
+ boolean isValidJoin(PlanNode joinNode, PlanNode sourceNode, AnalysisRecord
analysisRecord) throws QueryMetadataException, TeiidComponentException {
JoinType jtype = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
// Check that join is not a CROSS join or FULL OUTER join
if(jtype.equals(JoinType.JOIN_CROSS) || jtype.equals(JoinType.JOIN_FULL_OUTER))
{
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Rejecting dependent access node as parent join is
CROSS or FULL OUTER: "+ sourceNode.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode.recordDebugAnnotation("parent join is CROSS or FULL OUTER",
null, "Rejecting dependent join", analysisRecord, null); //$NON-NLS-1$
//$NON-NLS-2$
return false;
}
if (!joinNode.getExportedCorrelatedReferences().isEmpty()) {
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Rejecting dependent access node as parent join has
a correlated nested table: "+ sourceNode.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode.recordDebugAnnotation("parent join has a correlated nested
table", null, "Rejecting dependent join", analysisRecord, null);
//$NON-NLS-1$ //$NON-NLS-2$
return false;
}
// Check that join criteria exist
List jcrit = (List) joinNode.getProperty(NodeConstants.Info.JOIN_CRITERIA);
if(jcrit == null || jcrit.size() == 0) {
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Rejecting dependent access node as parent join has
no join criteria: "+ sourceNode.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode.recordDebugAnnotation("parent join has has no join
criteria", null, "Rejecting dependent join", analysisRecord, null);
//$NON-NLS-1$ //$NON-NLS-2$
return false;
}
if(joinNode.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS) == null) {
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Rejecting dependent access node as parent join has
no equality expressions: "+ sourceNode.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode.recordDebugAnnotation("parent join has no equa-join
predicates", null, "Rejecting dependent join", analysisRecord, null);
//$NON-NLS-1$ //$NON-NLS-2$
return false;
}
// Check that for a left or right outer join the dependent side must be the inner
if(jtype.isOuter() && JoinUtil.getInnerSideJoinNodes(joinNode)[0] !=
sourceNode) {
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Rejecting dependent access node as it is on outer
side of a join: "+ sourceNode.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode.recordDebugAnnotation("node is on outer side of the join",
null, "Rejecting dependent join", analysisRecord, null); //$NON-NLS-1$
//$NON-NLS-2$
return false;
}
return true;
}
- PlanNode chooseDepWithoutCosting(PlanNode rootNode1, PlanNode rootNode2,
AnalysisRecord analysisRecord) {
+ PlanNode chooseDepWithoutCosting(PlanNode rootNode1, PlanNode rootNode2,
AnalysisRecord analysisRecord) throws QueryMetadataException, TeiidComponentException {
PlanNode sourceNode1 = FrameUtil.findJoinSourceNode(rootNode1);
PlanNode sourceNode2 = null;
@@ -227,41 +221,30 @@
if (sourceNode2 != null &&
sourceNode2.hasCollectionProperty(NodeConstants.Info.ACCESS_PATTERNS) ) {
//Return null - query planning should fail because both access nodes
//have unsatisfied access patterns
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Neither access node can be made dependent
because both have unsatisfied access patterns: " + sourceNode1.nodeToString() +
"\n" + sourceNode2.toString()); //$NON-NLS-1$ //$NON-NLS-2$
- }
+ rootNode1.getParent().recordDebugAnnotation("both children have
unsatisfied access patterns", null, "Neither node can be made dependent",
analysisRecord, null); //$NON-NLS-1$ //$NON-NLS-2$
return null;
}
+ rootNode1.recordDebugAnnotation("unsatisfied access pattern
detected", null, "marking as dependent side of join", analysisRecord,
null); //$NON-NLS-1$ //$NON-NLS-2$
return rootNode1;
} else if (sourceNode2 != null &&
sourceNode2.hasCollectionProperty(NodeConstants.Info.ACCESS_PATTERNS) ) {
//Access node 2 has unsatisfied access pattern,
//so try to make node 2 dependent
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Making access node dependent to satisfy access
pattern: "+ sourceNode2.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode2.recordDebugAnnotation("unsatisfied access pattern
detected", null, "marking as dependent side of join", analysisRecord,
null); //$NON-NLS-1$ //$NON-NLS-2$
return rootNode2;
}
// Check for hints, which over-rule heuristics
if(sourceNode1.hasBooleanProperty(NodeConstants.Info.MAKE_DEP)) {
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Making access node dependent due to hint: "+
sourceNode1.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode1.recordDebugAnnotation("MAKE_DEP hint detected", null,
"marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$
//$NON-NLS-2$
return rootNode1;
} else if(sourceNode2 != null &&
sourceNode2.hasBooleanProperty(NodeConstants.Info.MAKE_DEP)) {
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Making access node dependent due to hint: "+
sourceNode2.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode2.recordDebugAnnotation("MAKE_DEP hint detected", null,
"marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$
//$NON-NLS-2$
return rootNode2;
} else if (sourceNode1.hasBooleanProperty(NodeConstants.Info.MAKE_IND) &&
sourceNode2 != null) {
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Making access node dependent due to hint: "+
sourceNode2.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode2.recordDebugAnnotation("MAKE_IND hint detected", null,
"marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$
//$NON-NLS-2$
return rootNode2;
} else if (sourceNode2 != null &&
sourceNode2.hasBooleanProperty(NodeConstants.Info.MAKE_IND)) {
- if (analysisRecord.recordDebug()) {
- analysisRecord.println("Making access node dependent due to hint: "+
sourceNode1.nodeToString()); //$NON-NLS-1$
- }
+ sourceNode1.recordDebugAnnotation("MAKE_IND hint detected", null,
"marking as dependent side of join", analysisRecord, null); //$NON-NLS-1$
//$NON-NLS-2$
return rootNode1;
}
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -168,7 +168,7 @@
// Walk to end of the chain and change recurse root
while(recurseRoot.getType() == NodeConstants.Types.SELECT) {
// Look for opportunities to replace with a semi-join
- recurseRoot = planMergeJoin(recurseRoot, root, analysisRecord);
+ recurseRoot = planMergeJoin(recurseRoot, root);
if (root.getChildCount() == 0) {
root = recurseRoot.getFirstChild();
if (root.getType() != NodeConstants.Types.SELECT) {
@@ -240,10 +240,8 @@
* IN ( ) / SOME ( )
*
* and replace with a semi join
- *
- * TODO: it would be good to have a hint to force
*/
- private PlanNode planMergeJoin(PlanNode current, PlanNode root, AnalysisRecord
analysisRecord) throws QueryMetadataException,
+ private PlanNode planMergeJoin(PlanNode current, PlanNode root) throws
QueryMetadataException,
TeiidComponentException {
float sourceCost = NewCalculateCostUtil.computeCostForTree(current.getFirstChild(),
metadata);
Criteria crit = (Criteria)current.getProperty(NodeConstants.Info.SELECT_CRITERIA);
@@ -270,7 +268,7 @@
if (!planQuery(leftGroups, false, plannedResult)) {
if (plannedResult.mergeJoin && analysisRecord != null &&
analysisRecord.recordAnnotations()) {
- this.analysisRecord.addAnnotation(new Annotation(Annotation.HINTS, "could not
plan as a merge join: " + crit, "ignoring hint", Priority.MEDIUM));
//$NON-NLS-1$ //$NON-NLS-2$
+ this.analysisRecord.addAnnotation(new Annotation(Annotation.HINTS, "Could not
plan as a merge join: " + crit, "ignoring MJ hint", Priority.HIGH));
//$NON-NLS-1$ //$NON-NLS-2$
}
return current;
}
@@ -287,9 +285,6 @@
List<Expression> projectedSymbols =
LanguageObject.Util.deepClone(plannedResult.query.getProjectedSymbols(),
Expression.class);
//NOTE: we could tap into the relationalplanner at a lower level to get this in a plan
node form,
//the major benefit would be to reuse the dependent join planning logic if possible.
- if (analysisRecord != null && analysisRecord.recordDebug()) {
- analysisRecord.println("Attempting to plan " + crit + " as a merge
join"); //$NON-NLS-1$ //$NON-NLS-2$
- }
RelationalPlan subPlan =
(RelationalPlan)QueryOptimizer.optimizePlan(plannedResult.query, metadata, idGenerator,
capFinder, analysisRecord, context);
Number planCardinality = subPlan.getRootNode().getEstimateNodeCardinality();
@@ -301,12 +296,14 @@
|| (sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE && sourceCost
* originalCardinality.floatValue() < planCardinality.floatValue() / (100 *
Math.log(Math.max(4, sourceCost))))) {
//bail-out if both are unknown or the new plan is too large
if (analysisRecord != null && analysisRecord.recordDebug()) {
- analysisRecord.println("Failed to use mege join, as the cost was not
favorable. Use the MJ hint to force."); //$NON-NLS-1$
+ current.recordDebugAnnotation("cost of merge join plan was not
favorable", null, "semi merge join will not be used", analysisRecord,
metadata); //$NON-NLS-1$ //$NON-NLS-2$
}
return current;
}
}
+ current.recordDebugAnnotation("Conditions met (hint or cost)", null,
"Converting to a semi merge join", analysisRecord, metadata); //$NON-NLS-1$
//$NON-NLS-2$
+
PlanNode semiJoin = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
semiJoin.addGroups(current.getGroups());
semiJoin.setProperty(NodeConstants.Info.JOIN_STRATEGY,
JoinStrategyType.MERGE);
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -232,9 +232,7 @@
Expression limit =
(Expression)parentNode.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT);
if (limit != null && !CapabilitiesUtil.supportsRowLimit(modelID,
metadata, capFinder)) {
- if (analysisRecord != null && analysisRecord.recordDebug()) {
- analysisRecord.println("limit not supported by source " +
metadata.getName(modelID)); //$NON-NLS-1$
- }
+ parentNode.recordDebugAnnotation("limit not supported by source",
modelID, "limit node not pushed", analysisRecord, metadata); //$NON-NLS-1$
//$NON-NLS-2$
return null;
}
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 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -144,13 +144,13 @@
{
// If model supports the support constant parameter, then move access
node
if(!CapabilitiesUtil.supportsSelectDistinct(modelID, metadata,
capFinder)) {
- recordDebug("cannot push dupremove, since distinct is not supported
by source", parentNode, record); //$NON-NLS-1$
+ parentNode.recordDebugAnnotation("distinct is not supported by
source", modelID, "cannot push dupremove", record, metadata); //$NON-NLS-1$
//$NON-NLS-2$
return null;
}
//TODO: this check is too specific the columns could be used in
expressions that are comparable
if
(!CapabilitiesUtil.checkElementsAreSearchable((List)NodeEditor.findNodePreOrder(parentNode,
NodeConstants.Types.PROJECT).getProperty(NodeConstants.Info.PROJECT_COLS), metadata,
SupportConstants.Element.SEARCHABLE_COMPARE)) {
- recordDebug("cannot push dupremove, since not all columns are
comparable at the source", parentNode, record); //$NON-NLS-1$
+ parentNode.recordDebugAnnotation("not all columns are comparable at
the source", modelID, "cannot push dupremove", record, metadata);
//$NON-NLS-1$ //$NON-NLS-2$
return null;
}
@@ -310,12 +310,12 @@
}
List<Expression> groupCols =
(List<Expression>)groupNode.getProperty(NodeConstants.Info.GROUP_COLS);
if(!CapabilitiesUtil.supportsAggregates(groupCols, modelID, metadata, capFinder))
{
- recordDebug("cannot push group by, since group by is not supported by
source", groupNode, record); //$NON-NLS-1$
+ groupNode.recordDebugAnnotation("group by is not supported by source",
modelID, "cannot push group by", record, metadata); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
if (CapabilitiesUtil.supports(Capability.QUERY_ONLY_SINGLE_TABLE_GROUP_BY,
modelID, metadata, capFinder)
&& !NodeEditor.findAllNodes(groupNode, NodeConstants.Types.JOIN,
NodeConstants.Types.SOURCE).isEmpty()) {
- recordDebug("cannot push group by, since joined group by is not supported
by source", groupNode, record); //$NON-NLS-1$
+ groupNode.recordDebugAnnotation("joined group by is not supported by
source", modelID, "cannot push group by", record, metadata); //$NON-NLS-1$
//$NON-NLS-2$
return false;
}
if (groupCols != null) {
@@ -335,13 +335,7 @@
return CapabilitiesUtil.checkElementsAreSearchable(groupCols, metadata,
SupportConstants.Element.SEARCHABLE_COMPARE);
}
- private static void recordDebug(String message, PlanNode node, AnalysisRecord record) {
- if (record != null && record.recordDebug()) {
- record.println(message + " " + node.nodeToString()); //$NON-NLS-1$
- }
- }
-
- static boolean canRaiseOverSort(PlanNode accessNode,
+ static boolean canRaiseOverSort(PlanNode accessNode,
QueryMetadataInterface metadata,
CapabilitiesFinder capFinder,
PlanNode parentNode, AnalysisRecord record, boolean
compensateForUnrelated) throws QueryMetadataException,
@@ -421,7 +415,7 @@
}
if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_HAVING) &&
!CapabilitiesUtil.supports(Capability.QUERY_HAVING, modelID, metadata, capFinder)) {
- recordDebug("cannot push having, since having is not supported by
source", parentNode, record); //$NON-NLS-1$
+ parentNode.recordDebugAnnotation("having is not supported by source",
modelID, "cannot push having", record, metadata); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -161,10 +161,7 @@
joinNode.removeChild(optionalNode);
joinNode.getFirstChild().setProperty(NodeConstants.Info.OUTPUT_COLS,
joinNode.getProperty(NodeConstants.Info.OUTPUT_COLS));
NodeEditor.removeChildNode(parentNode, joinNode);
- if (record != null && record.recordDebug()) {
- record.println("Removing join node since " + (isOptional?"it was marked
as optional ":"it will not affect the results") + joinNode); //$NON-NLS-1$
//$NON-NLS-2$ //$NON-NLS-3$
- }
-
+ joinNode.recordDebugAnnotation((isOptional?"node was marked as optional
":"node will not affect the results"), null, "Removing join
node", record, null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
while (parentNode.getType() != NodeConstants.Types.PROJECT) {
PlanNode current = parentNode;
parentNode = parentNode.getParent();
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/xml/XMLQueryPlanner.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/optimizer/xml/XMLQueryPlanner.java 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/main/java/org/teiid/query/optimizer/xml/XMLQueryPlanner.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -35,6 +35,7 @@
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.api.exception.query.QueryResolverException;
+import org.teiid.client.plan.Annotation.Priority;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.query.QueryPlugin;
@@ -482,25 +483,25 @@
ProcessorPlan plan = null;
- boolean debug = planEnv.analysisRecord.recordDebug();
+ boolean debug = planEnv.analysisRecord.recordAnnotations();
- if (debug) {
- planEnv.analysisRecord.println("Attempting to create plan for staging
table " + srcGroupName); //$NON-NLS-1$
- }
-
try {
// register with env
plan = optimizePlan(cmd, planEnv);
} catch (QueryPlannerException e) {
if (implicit) {
if (debug) {
- planEnv.analysisRecord.println("Failed to create plan for
staging table " + srcGroupName + " due to " + e.getMessage());
//$NON-NLS-1$ //$NON-NLS-2$
+ planEnv.analysisRecord.addAnnotation("XML Planning",
"Planning failded for staging otable " + srcGroupName + " due to " +
e.getMessage(), "Implicit staging table will not be used", Priority.LOW);
//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
return false;
}
throw e;
}
+ if (debug) {
+ planEnv.analysisRecord.addAnnotation("XML Planning", "Planning
succeeded for staging of " + srcGroupName, (implicit?"Implicit
":"") + "staging table will be used", Priority.MEDIUM);
//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+
int cardinality = QueryMetadataInterface.UNKNOWN_CARDINALITY;
if (plan instanceof RelationalPlan) {
Modified:
trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -68,6 +68,7 @@
import net.sf.saxon.value.SequenceType;
import org.teiid.api.exception.query.QueryResolverException;
+import org.teiid.client.plan.Annotation.Priority;
import org.teiid.common.buffer.BufferManager;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
@@ -90,6 +91,7 @@
@SuppressWarnings("serial")
public class SaxonXQueryExpression {
+ private static final String XQUERY_PLANNING = "XQuery Planning";
//$NON-NLS-1$
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
static final String DEFAULT_PREFIX = "-"; //$NON-NLS-1$
@@ -237,8 +239,8 @@
try {
streamingPath = StreamingUtils.getStreamingPath(xQueryString, namespaceMap);
} catch (IllegalArgumentException e) {
- if (record.recordDebug()) {
- record.println("Document streaming will not be used: " + e.getMessage());
//$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "Invalid streaming path " +
xQueryString + " "+ e.getMessage(), "Document streaming will not be
used", Priority.MEDIUM); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
this.contextRoot = null;
@@ -253,16 +255,16 @@
try {
parentRoot = map.getContextRoot();
} catch (IllegalStateException e) {
- if (record.recordDebug()) {
- record.println("Document projection will not be used, since multiple context
item exist."); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "Multiple context items exist " +
xQueryString, "Document projection will not be used", Priority.MEDIUM);
//$NON-NLS-1$ //$NON-NLS-2$
}
return;
}
if (parentRoot == null) {
//TODO: this seems like we could omit the context item altogether
//this.xQuery.usesContextItem() should also be false
- if (record.recordDebug()) {
- record.println("Document projection will not be used, since no context item
reference was found in the XQuery"); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "No context item reference was found in
the XQuery " + xQueryString, "Document projection will not be used",
Priority.MEDIUM); //$NON-NLS-1$ //$NON-NLS-2$
}
return;
}
@@ -272,8 +274,8 @@
if (!finalNodes.isEmpty()) {
if (columns != null && !columns.isEmpty()) {
if (finalNodes.size() != 1) {
- if (record.recordDebug()) {
- record.println("Document projection will not be used, since multiple return
items exist"); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "multiple return items exist " +
xQueryString, "Document projection will not be used", Priority.MEDIUM);
//$NON-NLS-1$ //$NON-NLS-2$
}
return;
}
@@ -289,15 +291,18 @@
}
}
if (parentRoot.hasUnknownDependencies()) {
- if (record.recordDebug()) {
- record.println("Document projection will not be used since there are unknown
dependencies (most likely a user defined function)."); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "There are unknown dependencies (most
likely a user defined function) in " + xQueryString, "Document projection will
not be used", Priority.MEDIUM); //$NON-NLS-1$ //$NON-NLS-2$
}
return;
}
- if (record.recordDebug()) {
- StringBuilder sb = new StringBuilder();
- showArcs(sb, parentRoot, 0);
- record.println("Using path filtering for XQuery context item: \n" +
sb.toString()); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ StringBuilder sb = null;
+ if (record.recordDebug()) {
+ sb = new StringBuilder();
+ showArcs(sb, parentRoot, 0);
+ }
+ record.addAnnotation(XQUERY_PLANNING, "Projection conditions met for " +
xQueryString, "Document projection will be used" + (sb != null ? "\n"
+sb.toString():""), Priority.MEDIUM); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
//$NON-NLS-4$
}
this.contextRoot = parentRoot;
}
@@ -331,8 +336,8 @@
for (PathMapRoot root : subMap.getPathMapRoots()) {
if (root.getRootExpression() instanceof ContextItemExpression ||
root.getRootExpression() instanceof RootExpression) {
if (subContextRoot != null) {
- if (record.recordDebug()) {
- record.println("Document projection will not be used, since multiple context
items exist in column path " + xmlColumn.getPath()); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "Multiple context items exist in column
path " + xmlColumn.getPath(), "Document projection will not be used",
Priority.MEDIUM); //$NON-NLS-1$ //$NON-NLS-2$
}
return null;
}
@@ -387,15 +392,15 @@
if (ancestor) {
if (current.getTarget().isReturnable()) {
if (axis != Axis.NAMESPACE && axis != Axis.ATTRIBUTE) {
- if (record.recordDebug()) {
- record.println("Document streaming will not be used, since the column path
contains an invalid reverse axis " + xmlColumn.getPath()); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "The column path contains an invalid
reverse axis " + xmlColumn.getPath(), "Document streaming will not be
used", Priority.MEDIUM); //$NON-NLS-1$ //$NON-NLS-2$
}
return false;
}
}
if (!isValidAncestorAxis[axis]) {
- if (record.recordDebug()) {
- record.println("Document streaming will not be used, since the column path
contains an invalid reverse axis " + xmlColumn.getPath()); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "The column path contains an invalid
reverse axis " + xmlColumn.getPath(), "Document streaming will not be
used", Priority.MEDIUM); //$NON-NLS-1$ //$NON-NLS-2$
}
return false;
}
@@ -404,15 +409,15 @@
|| axis == Axis.ANCESTOR
|| axis == Axis.ANCESTOR_OR_SELF) {
if (current.getTarget().isReturnable()) {
- if (record.recordDebug()) {
- record.println("Document streaming will not be used, since the column path
contains an invalid reverse axis " + xmlColumn.getPath()); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "The column path contains an invalid
reverse axis " + xmlColumn.getPath(), "Document streaming will not be
used", Priority.MEDIUM); //$NON-NLS-1$ //$NON-NLS-2$
}
return false;
}
ancestor = true;
} else {
- if (record.recordDebug()) {
- record.println("Document streaming will not be used, since the column path may
not reference an ancestor or subtree " + xmlColumn.getPath()); //$NON-NLS-1$
+ if (record.recordAnnotations()) {
+ record.addAnnotation(XQUERY_PLANNING, "The column path may not reference an
ancestor or subtree " + xmlColumn.getPath(), "Document streaming will not be
used", Priority.MEDIUM); //$NON-NLS-1$ //$NON-NLS-2$
}
return false;
}
Modified:
trunk/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java 2012-05-21
15:16:44 UTC (rev 4129)
+++
trunk/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java 2012-05-21
15:54:43 UTC (rev 4130)
@@ -47,17 +47,7 @@
import org.teiid.query.processor.relational.JoinNode.JoinStrategyType;
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.rewriter.QueryRewriter;
-import org.teiid.query.sql.lang.CompareCriteria;
-import org.teiid.query.sql.lang.CompoundCriteria;
-import org.teiid.query.sql.lang.Criteria;
-import org.teiid.query.sql.lang.From;
-import org.teiid.query.sql.lang.IsNullCriteria;
-import org.teiid.query.sql.lang.JoinType;
-import org.teiid.query.sql.lang.MatchCriteria;
-import org.teiid.query.sql.lang.NotCriteria;
-import org.teiid.query.sql.lang.Query;
-import org.teiid.query.sql.lang.Select;
-import org.teiid.query.sql.lang.SetCriteria;
+import org.teiid.query.sql.lang.*;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.GroupSymbol;
@@ -162,7 +152,7 @@
return query;
}
- public void helpTestValidJoin(PlanNode joinNode, PlanNode accessNode, boolean
expectedValid) {
+ public void helpTestValidJoin(PlanNode joinNode, PlanNode accessNode, boolean
expectedValid) throws QueryMetadataException, TeiidComponentException {
RuleChooseDependent rule = new RuleChooseDependent();
RuleChooseJoinStrategy.chooseJoinStrategy(joinNode, metadata);
boolean isValid = rule.isValidJoin(joinNode, accessNode,
AnalysisRecord.createNonRecordingRecord());