[teiid-commits] teiid SVN: r4130 - in trunk: engine/src/main/java/org/teiid/query/analysis and 5 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Mon May 21 11:54:44 EDT 2012


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());



More information about the teiid-commits mailing list