[teiid-commits] teiid SVN: r2597 - in branches/7.1.x: engine/src/main/java/org/teiid/query/optimizer/relational/plantree and 2 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Wed Sep 22 17:14:19 EDT 2010


Author: shawkins
Date: 2010-09-22 17:14:19 -0400 (Wed, 22 Sep 2010)
New Revision: 2597

Modified:
   branches/7.1.x/documentation/developer-guide/src/main/docbook/en-US/content/translator-api.xml
   branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java
   branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
   branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java
   branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
   branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java
   branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
   branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
   branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
   branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
   branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCalculateCostUtil.java
   branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCriteriaCapabilityValidatorVisitor.java
   branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java
Log:
TEIID-1271 adding some logging for common pushdown decisions.  there are still plenty more to add.   TEIID-1272 making join ordering decisions use a better heuristic when 1 side is unknown

Modified: branches/7.1.x/documentation/developer-guide/src/main/docbook/en-US/content/translator-api.xml
===================================================================
--- branches/7.1.x/documentation/developer-guide/src/main/docbook/en-US/content/translator-api.xml	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/documentation/developer-guide/src/main/docbook/en-US/content/translator-api.xml	2010-09-22 21:14:19 UTC (rev 2597)
@@ -680,10 +680,10 @@
     <title>Translator Capabilities</title>
 	<para>The <code>ExecutionFactory</code> class defines all the methods that describe the capabilities of a Translator. 
        These are used by the Connector Manager to determine what kinds of commands the translator is
-		capable of executing. A base  <code>ExecutionFactory</code> class implements all the basic capabilities, which says
-        your translator does not support any cpabilities. Your extended 
+		capable of executing. A base  <code>ExecutionFactory</code> class implements all the basic capabilities methods, which says
+        your translator does not support any capabilities. Your extended 
         <code>ExecutionFactory</code> class must override the the necessary methods to specify which
-		capabilities your translator supports.  </para>
+		capabilities your translator supports.  You should consult the debug log of query planning (set showplan debug) to see if desired pushdown requires additional capabilities.</para>
     <section>
       <title>Capability Scope</title>
 		<para>

Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -378,5 +378,13 @@
 		}
 		return ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(toSearch);
 	}
+	
+	public float getCardinality() {
+		Float cardinality = (Float) this.getProperty(NodeConstants.Info.EST_CARDINALITY);
+		if (cardinality == null) {
+			return -1f;
+		}
+		return cardinality;
+	}
         
 }

Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -28,6 +28,7 @@
 import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.query.QueryPlugin;
+import org.teiid.query.analysis.AnalysisRecord;
 import org.teiid.query.function.metadata.FunctionMethod;
 import org.teiid.query.metadata.QueryMetadataInterface;
 import org.teiid.query.metadata.SupportConstants;
@@ -83,6 +84,7 @@
     private Object modelID;
     private QueryMetadataInterface metadata;
     private CapabilitiesFinder capFinder;
+    private AnalysisRecord analysisRecord;
 
     // Retrieved during initialization and cached
     private SourceCapabilities caps;
@@ -105,48 +107,48 @@
     
     @Override
     public void visit(XMLAttributes obj) {
-    	markInvalid();
+    	markInvalid(obj, "Pushdown of XMLAttributes not allowed"); //$NON-NLS-1$
     }
     
     @Override
     public void visit(XMLNamespaces obj) {
-    	markInvalid();
+    	markInvalid(obj, "Pushdown of XMLNamespaces not allowed"); //$NON-NLS-1$
     }
     
     @Override
     public void visit(XMLForest obj) {
-    	markInvalid();
+    	markInvalid(obj, "Pushdown of XMLForest not allowed"); //$NON-NLS-1$
     }
     
     @Override
     public void visit(XMLElement obj) {
-    	markInvalid();
+    	markInvalid(obj, "Pushdown of XMLElement not allowed"); //$NON-NLS-1$
     }
     
     @Override
     public void visit(XMLSerialize obj) {
-    	markInvalid();
+    	markInvalid(obj, "Pushdown of XMLSerialize not allowed"); //$NON-NLS-1$
     }
     
     @Override
     public void visit(XMLParse obj) {
-    	markInvalid();
+    	markInvalid(obj, "Pushdown of XMLParse not allowed"); //$NON-NLS-1$
     }
     
     @Override
     public void visit(XMLQuery obj) {
-    	markInvalid();
+    	markInvalid(obj, "Pushdown of XMLQuery not allowed"); //$NON-NLS-1$
     }
     
     @Override
     public void visit(QueryString obj) {
-    	markInvalid();
+    	markInvalid(obj, "Pushdown of QueryString not allowed"); //$NON-NLS-1$
     }
     
     public void visit(AggregateSymbol obj) {
         try {
             if(! CapabilitiesUtil.supportsAggregateFunction(modelID, obj, metadata, capFinder)) {
-                markInvalid();
+                markInvalid(obj, "Aggregate function pushdown not supported by source"); //$NON-NLS-1$
             }         
         } catch(QueryMetadataException e) {
             handleException(new TeiidComponentException(e));
@@ -157,7 +159,7 @@
     
     public void visit(CaseExpression obj) {
         if(! this.caps.supportsCapability(Capability.QUERY_CASE)) {
-            markInvalid();
+            markInvalid(obj, "CaseExpression pushdown not supported by source"); //$NON-NLS-1$
         }
     }
     
@@ -186,10 +188,12 @@
 
         // Check if compares are allowed
         if(! this.caps.supportsCapability(operatorCap)) {
-            markInvalid();
+            markInvalid(obj, "ordered CompareCriteria not supported by source"); //$NON-NLS-1$
+            return;
         }                       
         if (negated && !this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
-        	markInvalid();
+        	markInvalid(obj, "Negation is not supported by source"); //$NON-NLS-1$
+        	return;
         }
         
         // Check capabilities of the elements
@@ -206,12 +210,8 @@
         int operator = crit.getOperator();
         
         // Verify capabilities are supported
-        if(operator == CompoundCriteria.OR) {
-            // Check if OR is allowed
-            if(! this.caps.supportsCapability(Capability.CRITERIA_OR)) {
-                markInvalid();
-                return;
-            }                       
+        if(operator == CompoundCriteria.OR && !this.caps.supportsCapability(Capability.CRITERIA_OR)) {
+                markInvalid(crit, "OR criteria not supported by source"); //$NON-NLS-1$
         }
     }
 
@@ -221,9 +221,13 @@
             if (EvaluatableVisitor.willBecomeConstant(obj, true)) { 
                 return; 
             }
-            if(obj.getFunctionDescriptor().getPushdown() == FunctionMethod.CANNOT_PUSHDOWN || ! CapabilitiesUtil.supportsScalarFunction(modelID, obj, metadata, capFinder)) {
-                markInvalid();
+            if(obj.getFunctionDescriptor().getPushdown() == FunctionMethod.CANNOT_PUSHDOWN) {
+            	markInvalid(obj, "Function metadata indicates it cannot be pusheddown."); //$NON-NLS-1$
+            	return;
             }
+            if (! CapabilitiesUtil.supportsScalarFunction(modelID, obj, metadata, capFinder)) {
+                markInvalid(obj, obj.isImplicit()?"":"(implicit) convert" + " Function not supported by source"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+            }
         } catch(QueryMetadataException e) {
             handleException(new TeiidComponentException(e));
         } catch(TeiidComponentException e) {
@@ -234,12 +238,12 @@
     public void visit(IsNullCriteria obj) {
         // Check if compares are allowed
         if(! this.caps.supportsCapability(Capability.CRITERIA_ISNULL)) {
-            markInvalid();
+            markInvalid(obj, "IsNull not supported by source"); //$NON-NLS-1$
             return;
         }
         
         if (obj.isNegated() && !this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
-        	markInvalid();
+        	markInvalid(obj, "Negation is not supported by source"); //$NON-NLS-1$
             return;
         }        
     }
@@ -247,21 +251,21 @@
     public void visit(MatchCriteria obj) {
         // Check if compares are allowed
         if(! this.caps.supportsCapability(Capability.CRITERIA_LIKE)) {
-            markInvalid();
+            markInvalid(obj, "Like is not supported by source"); //$NON-NLS-1$
             return;
         }
         
         // Check ESCAPE char if necessary
         if(obj.getEscapeChar() != MatchCriteria.NULL_ESCAPE_CHAR) {
             if(! this.caps.supportsCapability(Capability.CRITERIA_LIKE_ESCAPE)) {
-                markInvalid();
+                markInvalid(obj, "Like escape is not supported by source"); //$NON-NLS-1$
                 return;
             }                
         }
         
         //check NOT
         if(obj.isNegated() && ! this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
-        	markInvalid();
+        	markInvalid(obj, "Negation is not supported by source"); //$NON-NLS-1$
         	return;
         }
 
@@ -278,18 +282,14 @@
     public void visit(NotCriteria obj) {
         // Check if compares are allowed
         if(! this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
-            markInvalid();
+            markInvalid(obj, "Negation is not supported by source"); //$NON-NLS-1$
             return;
         }
     }
 
     public void visit(SearchedCaseExpression obj) {
-        if (this.caps == null) {
-            return;
-        }
-         
         if(! this.caps.supportsCapability(Capability.QUERY_SEARCHED_CASE)) {
-            markInvalid();
+            markInvalid(obj, "SearchedCase is not supported by source"); //$NON-NLS-1$
         }
     }
     
@@ -299,7 +299,7 @@
             int maxSize = CapabilitiesUtil.getMaxInCriteriaSize(modelID, metadata, capFinder); 
             
             if (maxSize > 0 && crit.getValues().size() > maxSize) {
-                markInvalid();
+                markInvalid(crit, "SetCriteria size exceeds maximum for source"); //$NON-NLS-1$
                 return;
             }
         } catch(QueryMetadataException e) {
@@ -315,13 +315,13 @@
     public void visit(ExistsCriteria crit) {
         // Check if exists criteria are allowed
         if(! this.caps.supportsCapability(Capability.CRITERIA_EXISTS)) {
-            markInvalid();
+            markInvalid(crit, "Exists is not supported by source"); //$NON-NLS-1$
             return;
         }
         
         try {
-			if (validateSubqueryPushdown(crit, modelID, metadata, capFinder) == null) {
-				markInvalid();
+			if (validateSubqueryPushdown(crit, modelID, metadata, capFinder, analysisRecord) == null) {
+				markInvalid(crit.getCommand(), "Subquery cannot be pushed down"); //$NON-NLS-1$
 			}
 		} catch (TeiidComponentException e) {
 			handleException(e);
@@ -346,7 +346,7 @@
                 break;
         }
         if(! this.caps.supportsCapability(capability)) {
-            markInvalid();
+            markInvalid(crit, "SubqueryCompare not supported by source"); //$NON-NLS-1$
             return;
         }
         
@@ -354,8 +354,8 @@
         
         // Check capabilities of the elements
         try {
-            if (validateSubqueryPushdown(crit, modelID, metadata, capFinder) == null) {
-            	markInvalid();
+            if (validateSubqueryPushdown(crit, modelID, metadata, capFinder, analysisRecord) == null) {
+            	markInvalid(crit.getCommand(), "Subquery cannot be pushed down"); //$NON-NLS-1$
             }
         } catch(QueryMetadataException e) {
             handleException(new TeiidComponentException(e));
@@ -368,11 +368,12 @@
     public void visit(ScalarSubquery obj) {
     	try {    
             if(!this.caps.supportsCapability(Capability.QUERY_SUBQUERIES_SCALAR) 
-            		|| validateSubqueryPushdown(obj, modelID, metadata, capFinder) == null) {
+            		|| validateSubqueryPushdown(obj, modelID, metadata, capFinder, analysisRecord) == null) {
             	if (obj.getCommand().getCorrelatedReferences() == null) {
             		obj.setShouldEvaluate(true);
             	} else {
-            		markInvalid();
+            		markInvalid(obj.getCommand(), !this.caps.supportsCapability(Capability.QUERY_SUBQUERIES_SCALAR)?
+            				"Correlated ScalarSubquery is not supported":"Subquery cannot be pushed down"); //$NON-NLS-1$ //$NON-NLS-2$
             	}
             }
         } catch(QueryMetadataException e) {
@@ -387,12 +388,12 @@
         try {    
             // Check if compares with subqueries are allowed
             if(! this.caps.supportsCapability(Capability.CRITERIA_IN_SUBQUERY)) {
-                markInvalid();
+                markInvalid(crit, "SubqueryIn is not supported by source"); //$NON-NLS-1$
                 return;
             }
 
-            if (validateSubqueryPushdown(crit, modelID, metadata, capFinder) == null) {
-            	markInvalid();
+            if (validateSubqueryPushdown(crit, modelID, metadata, capFinder, analysisRecord) == null) {
+            	markInvalid(crit.getCommand(), "Subquery cannot be pushed down"); //$NON-NLS-1$
             }
         } catch(QueryMetadataException e) {
             handleException(new TeiidComponentException(e));
@@ -405,12 +406,12 @@
         try {    
             // Check if compares are allowed
             if(! this.caps.supportsCapability(Capability.CRITERIA_IN)) {
-                markInvalid();
+                markInvalid(crit, "In is not supported by source"); //$NON-NLS-1$
                 return;
             }
             
             if (crit.isNegated() && !this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
-            	markInvalid();
+            	markInvalid(crit, "Negation is not supported by source"); //$NON-NLS-1$
                 return;
             }
             // Check capabilities of the elements
@@ -431,7 +432,7 @@
     private void checkElementsAreSearchable(LanguageObject crit, int searchableType)
     throws QueryMetadataException, TeiidComponentException {
     	if (!CapabilitiesUtil.checkElementsAreSearchable(Arrays.asList(crit), metadata, searchableType)) {
-    		markInvalid();
+    		markInvalid(crit, "not all source columns support search type"); //$NON-NLS-1$
     	}
     }
     
@@ -445,7 +446,7 @@
      * @return
      * @throws TeiidComponentException
      */
-    static Object validateSubqueryPushdown(SubqueryContainer subqueryContainer, Object critNodeModelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws TeiidComponentException {
+    static Object validateSubqueryPushdown(SubqueryContainer subqueryContainer, Object critNodeModelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord) throws TeiidComponentException {
     	ProcessorPlan plan = subqueryContainer.getCommand().getProcessorPlan();
     	if (plan != null) {
 	        if(!(plan instanceof RelationalPlan)) {
@@ -497,7 +498,7 @@
                 }
                 //TODO: this check sees as correlated references as coming from the containing scope
                 //but this is only an issue with deeply nested subqueries
-                if (!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(subqueryContainer.getCommand(), critNodeModelID, metadata, capFinder)) {
+                if (!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(subqueryContainer.getCommand(), critNodeModelID, metadata, capFinder, analysisRecord )) {
                     return null;
                 }
             }
@@ -519,16 +520,19 @@
         return this.exception;
     }
     
-    private void markInvalid() {
+    private void markInvalid(LanguageObject object, String reason) {
         this.valid = false;
         setAbort(true);
+        if (analysisRecord != null && analysisRecord.recordDebug()) {
+        	analysisRecord.println(reason + " " + object); //$NON-NLS-1$
+        }
     }
     
     public boolean isValid() {
         return this.valid;
     }
 
-    public static boolean canPushLanguageObject(LanguageObject obj, Object modelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException {
+    public static boolean canPushLanguageObject(LanguageObject obj, Object modelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord) throws QueryMetadataException, TeiidComponentException {
         if(obj == null) {
             return true;
         }

Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -42,6 +42,7 @@
 import org.teiid.query.optimizer.relational.plantree.PlanNode;
 import org.teiid.query.resolver.util.AccessPattern;
 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.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
@@ -233,8 +234,10 @@
      * @param joinOrder
      * @param metadata
      * @return
+     * @throws TeiidComponentException 
+     * @throws QueryMetadataException 
      */
-    public double scoreRegion(Object[] joinOrder, QueryMetadataInterface metadata) {
+    public double scoreRegion(Object[] joinOrder, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
         List<Map.Entry<PlanNode, PlanNode>> joinSourceEntries = new ArrayList<Map.Entry<PlanNode, PlanNode>>(joinSourceNodes.entrySet());
         double totalIntermediatCost = 0;
         double cost = 1;
@@ -263,17 +266,35 @@
             
             float sourceCost = ((Float)joinSourceRoot.getProperty(NodeConstants.Info.EST_CARDINALITY)).floatValue();
             
-            if (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE) {
-                sourceCost = UNKNOWN_TUPLE_EST;
+            List<PlanNode> applicableCriteria = null;
+            
+            if (!criteria.isEmpty() && i > 0) {
+                applicableCriteria = getJoinCriteriaForGroups(groups, criteria);
+            }
+            
+        	if (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE) {
+        		sourceCost = UNKNOWN_TUPLE_EST;
+                if (applicableCriteria != null && !applicableCriteria.isEmpty()) {
+                	CompoundCriteria cc = new CompoundCriteria();
+                	for (PlanNode planNode : applicableCriteria) {
+    					cc.addCriteria((Criteria) planNode.getProperty(NodeConstants.Info.SELECT_CRITERIA));
+    				}
+                	sourceCost = (float)cost;
+                	criteria.removeAll(applicableCriteria);
+	            	applicableCriteria = null;
+            		if (NewCalculateCostUtil.usesKey(cc, metadata)) {
+    	            	sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * Math.min(NewCalculateCostUtil.UNKNOWN_JOIN_SCALING, sourceCost));
+            		} else {
+    	            	sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * Math.min(NewCalculateCostUtil.UNKNOWN_JOIN_SCALING * 2, sourceCost));
+            		}
+                }
             } else if (Double.isInfinite(sourceCost) || Double.isNaN(sourceCost)) {
-                sourceCost = UNKNOWN_TUPLE_EST * 10;
+            	return Double.MAX_VALUE;
             }
-            
+        
             cost *= sourceCost;
             
-            if (!criteria.isEmpty() && i > 0) {
-                List<PlanNode> applicableCriteria = getJoinCriteriaForGroups(groups, criteria);
-                
+            if (applicableCriteria != null) {
                 for (PlanNode criteriaNode : applicableCriteria) {
                     float filter = ((Float)criteriaNode.getProperty(NodeConstants.Info.EST_SELECTIVITY)).floatValue();
                     
@@ -282,7 +303,6 @@
                 
                 criteria.removeAll(applicableCriteria);
             }
-            
             totalIntermediatCost += cost;
         }
         

Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -76,7 +76,8 @@
  */
 public class NewCalculateCostUtil {
 
-    public static final float UNKNOWN_VALUE = -1;
+    public static final int UNKNOWN_JOIN_SCALING = 20;
+	public static final float UNKNOWN_VALUE = -1;
     
     // the following variables are used to hold cost estimates (roughly in milliseconds)
     private final static float compareTime = .05f; //TODO: a better estimate would be based upon the number of conjuncts
@@ -181,13 +182,13 @@
             case NodeConstants.Types.TUPLE_LIMIT: 
             {
                 PlanNode child = node.getFirstChild();
-                Float childCost = (Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY);
+                float childCost = child.getCardinality();
                 
                 Expression offset = (Expression)node.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT);
                 Float cost = childCost;
                 
-                if (childCost.floatValue() != UNKNOWN_VALUE && offset instanceof Constant) {
-                    float offsetCost = childCost.floatValue() - ((Number)((Constant)offset).getValue()).floatValue();
+                if (childCost != UNKNOWN_VALUE && offset instanceof Constant) {
+                    float offsetCost = childCost - ((Number)((Constant)offset).getValue()).floatValue();
                     cost = new Float((offsetCost < 0) ? 0 : offsetCost);
                 }
                 
@@ -277,39 +278,43 @@
     private static void estimateJoinNodeCost(PlanNode node, QueryMetadataInterface metadata)
         throws QueryMetadataException, TeiidComponentException {
 
-        Iterator children = node.getChildren().iterator();
-        PlanNode child1 = (PlanNode)children.next();
-        Float childCost1 = (Float)child1.getProperty(NodeConstants.Info.EST_CARDINALITY);
-        PlanNode child2 = (PlanNode)children.next();
-        Float childCost2 = (Float)child2.getProperty(NodeConstants.Info.EST_CARDINALITY);
-        if (childCost1 != null && childCost2 != null && childCost1.floatValue() != UNKNOWN_VALUE && childCost2.floatValue() != UNKNOWN_VALUE){
+        Iterator<PlanNode> children = node.getChildren().iterator();
+        PlanNode child1 = children.next();
+        float childCost1 = child1.getCardinality();
+        PlanNode child2 = children.next();
+        float childCost2 = child2.getCardinality();
+        
+        if (childCost1 == UNKNOWN_VALUE || childCost2 == UNKNOWN_VALUE) {
+        	setCardinalityEstimate(node, null);
+        	return;
+        }
 
-            JoinType joinType = (JoinType)node.getProperty(NodeConstants.Info.JOIN_TYPE);
-            List joinCriteria = (List) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
-            
-            float baseCost = childCost1.floatValue() * childCost2.floatValue();
-            if (joinCriteria != null && !joinCriteria.isEmpty()) {
-                Criteria crit = Criteria.combineCriteria(joinCriteria);
-                baseCost = recursiveEstimateCostOfCriteria(baseCost, node, crit, metadata);
-            }
-            
-            Float cost = null;
-            if (JoinType.JOIN_CROSS.equals(joinType)){
-                cost = new Float(baseCost);
-            } else if (JoinType.JOIN_FULL_OUTER.equals(joinType)) {
-                cost = new Float(Math.max((childCost1.floatValue()+childCost2.floatValue()),baseCost));
-            } else if (JoinType.JOIN_LEFT_OUTER.equals(joinType)) {
-                cost = new Float(Math.max(childCost1.floatValue(),baseCost));
-            } else if (JoinType.JOIN_RIGHT_OUTER.equals(joinType)) {
-                cost = new Float(Math.max(childCost2.floatValue(),baseCost));
-            } else if (JoinType.JOIN_INNER.equals(joinType)) {
-                cost = new Float(baseCost);
-            }
-            
-            setCardinalityEstimate(node, cost);
-        } else {
-            setCardinalityEstimate(node, null);
+        JoinType joinType = (JoinType)node.getProperty(NodeConstants.Info.JOIN_TYPE);
+        List joinCriteria = (List) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
+        
+        float baseCost = childCost1 * childCost2;
+
+        if (joinCriteria != null && !joinCriteria.isEmpty()) {
+    		Criteria crit = Criteria.combineCriteria(joinCriteria);
+    		//TODO: we may be able to get a fairly accurate join estimate if the
+    		//unknown side is being joined with a key
+        	baseCost = recursiveEstimateCostOfCriteria(baseCost, node, crit, metadata);
         }
+        
+        Float cost = null;
+        if (JoinType.JOIN_CROSS.equals(joinType)){
+            cost = new Float(baseCost);
+        } else if (JoinType.JOIN_FULL_OUTER.equals(joinType)) {
+            cost = new Float(Math.max((childCost1+childCost2),baseCost));
+        } else if (JoinType.JOIN_LEFT_OUTER.equals(joinType)) {
+            cost = new Float(Math.max(childCost1,baseCost));
+        } else if (JoinType.JOIN_RIGHT_OUTER.equals(joinType)) {
+            cost = new Float(Math.max(childCost2,baseCost));
+        } else if (JoinType.JOIN_INNER.equals(joinType)) {
+            cost = new Float(baseCost);
+        }
+        
+        setCardinalityEstimate(node, cost);
     }
 
     /**
@@ -321,11 +326,7 @@
         throws QueryMetadataException, TeiidComponentException {
 
         PlanNode child = node.getFirstChild();
-        Float childCostFloat = (Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY);
-        float childCost = UNKNOWN_VALUE;
-        if (childCostFloat != null){
-            childCost = childCostFloat.floatValue();    
-        }
+        float childCost = child.getCardinality();
         
         //Get list of conjuncts
         Criteria selectCriteria = (Criteria)node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
@@ -350,10 +351,7 @@
         	//only cost non-correlated TODO: a better estimate for correlated
         	if (references == null) {
 	            PlanNode child = node.getFirstChild();
-	            Float childCostFloat = (Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY);
-	            if (childCostFloat != null) {
-	                cost = childCostFloat.floatValue();
-	            }
+	            cost = child.getCardinality();
         	}
         }else {
             GroupSymbol group = node.getGroups().iterator().next();
@@ -379,7 +377,7 @@
         throws QueryMetadataException, TeiidComponentException {
         
         PlanNode child = node.getFirstChild();
-        float childCost = ((Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY)).floatValue();
+        float childCost = child.getCardinality();
         
         if(childCost == UNKNOWN_VALUE) {
             setCardinalityEstimate(node, null);
@@ -421,12 +419,9 @@
             if (compCrit.getOperator() == CompoundCriteria.OR) {
                 cost = 0;
             } 
-            HashSet<ElementSymbol> elements = new HashSet<ElementSymbol>();
-            collectElementsOfValidCriteria(compCrit, elements);
-            if (usesKey(elements, metadata)) {
+            if (usesKey(compCrit, metadata)) {
                 return 1;
             }
-
             for (Criteria critPart : compCrit.getCriteria()) {
                 float nextCost = recursiveEstimateCostOfCriteria(childCost, currentNode, critPart, metadata);
                 
@@ -497,7 +492,7 @@
        
         if(criteria instanceof CompoundCriteria) {
             CompoundCriteria compCrit = (CompoundCriteria) criteria;
-            Iterator iter = compCrit.getCriteria().iterator();
+            Iterator<Criteria> iter = compCrit.getCriteria().iterator();
             boolean first = true;
             Collection<ElementSymbol> savedElements = elements;
             if(compCrit.getOperator() == CompoundCriteria.OR) {
@@ -505,11 +500,11 @@
             }
             while(iter.hasNext()) { 
             	if(compCrit.getOperator() == CompoundCriteria.AND || first) {
-            		collectElementsOfValidCriteria((Criteria) iter.next(), elements);
+            		collectElementsOfValidCriteria(iter.next(), elements);
             		first = false;
             	} else {
             		HashSet<ElementSymbol> other = new HashSet<ElementSymbol>();
-            		collectElementsOfValidCriteria((Criteria) iter.next(), other);
+            		collectElementsOfValidCriteria(iter.next(), other);
             		elements.retainAll(other);
             	}
             }
@@ -532,7 +527,6 @@
             if (!setCriteria.isNegated()) {
                 ElementCollectorVisitor.getElements(setCriteria.getExpression(), elements);
             }
-
         } else if(criteria instanceof IsNullCriteria) {
             IsNullCriteria isNullCriteria = (IsNullCriteria)criteria;
             if (!isNullCriteria.isNegated()) {
@@ -769,6 +763,12 @@
     	&& usesKey(allElements, metadata);
     }
     
+    public static boolean usesKey(Criteria crit, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
+        HashSet<ElementSymbol> elements = new HashSet<ElementSymbol>();
+        collectElementsOfValidCriteria(crit, elements);
+        return usesKey(elements, metadata);
+    }
+    
     /**
      * TODO: this uses key check is not really accurate, it doesn't take into consideration where 
      * we are in the plan.
@@ -849,8 +849,8 @@
             	}
             } else if (cardinality != UNKNOWN_VALUE) {
             	int groupCardinality = metadata.getCardinality(elementSymbol.getGroupSymbol().getMetadataID());
-            	if (groupCardinality != UNKNOWN_VALUE) {
-            		ndv *= cardinality / Math.max(1, groupCardinality);
+            	if (groupCardinality != UNKNOWN_VALUE && groupCardinality > cardinality) {
+        			ndv *= cardinality / Math.max(1, groupCardinality);
             	}
             }
             result = Math.max(result, ndv);
@@ -948,7 +948,7 @@
     /**
      * Computes the cost of a Dependent Join
      * 
-     * The worst possible cost will arise from a high independent ndv (many dependent sets) and a low depenendent ndv (possibly many matches per set)
+     * The worst possible cost will arise from a high independent ndv (many dependent sets) and a low dependent ndv (possibly many matches per set)
      * 
      * This logic uses the same assumption as criteria in that ndv is used as a divisor of cardinality. 
      * 

Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -150,7 +150,7 @@
         	if (NewCalculateCostUtil.usesKey(sourceNode, expressions, metadata)) {
                 joinNode.setProperty(joinNode.getFirstChild() == childNode ? NodeConstants.Info.IS_LEFT_DISTINCT : NodeConstants.Info.IS_RIGHT_DISTINCT, true);
         	}
-	        if (attemptPush && RuleRaiseAccess.canRaiseOverSort(sourceNode, metadata, capFinder, sortNode)) {
+	        if (attemptPush && RuleRaiseAccess.canRaiseOverSort(sourceNode, metadata, capFinder, sortNode, null)) {
 	            sourceNode.getFirstChild().addAsParent(sortNode);
 	            
 	            if (needsCorrection) {

Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -237,7 +237,7 @@
                      *  Ideally we should be a little smarter in case 2 
                      *    - pushing down a same source cross join can be done if we know that a dependent join will be performed 
                      */
-                    boolean hasJoinCriteria = false; 
+                    //boolean hasJoinCriteria = false; 
                     LinkedList<Criteria> joinCriteria = new LinkedList<Criteria>();
                     Object modelId = RuleRaiseAccess.getModelIDFromAccess(accessNode1, metadata);
                     SupportedJoinCriteria sjc = CapabilitiesUtil.getSupportedJoinCriteria(modelId, metadata, capFinder);
@@ -250,25 +250,27 @@
                         
                         if (sources.contains(accessNode1)) {
                             if (sources.contains(accessNode2) && sources.size() == 2) {
-                                hasJoinCriteria = true;
+                                //hasJoinCriteria = true;
                                 Criteria crit = (Criteria)critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
-								if (RuleRaiseAccess.isSupportedJoinCriteria(sjc, crit, modelId, metadata, capFinder)) {
+								if (RuleRaiseAccess.isSupportedJoinCriteria(sjc, crit, modelId, metadata, capFinder, null)) {
 	                                joinCriteriaNodes.add(critNode);
 	                                joinCriteria.add(crit);
                                 }
                             } else if (!accessNodes.containsAll(sources)) {
-                                hasJoinCriteria = true;
+                                //hasJoinCriteria = true;
                             }
                         } else if (sources.contains(accessNode2) && !accessNodes.containsAll(sources)) {
-                            hasJoinCriteria = true;
+                           //hasJoinCriteria = true;
                         }
                     }
                     
                     /*
-                     * If we failed to find direct criteria, but still have non-pushable or criteria to
-                     * other groups we'll use additional checks
+                     * If we failed to find direct criteria, a cross join may still be acceptable
                      */
-                    if ((!hasJoinCriteria || joinCriteriaNodes.isEmpty()) && !canPushCrossJoin(metadata, context, accessNode1, accessNode2)) {
+                    if (joinCriteriaNodes.isEmpty() && !canPushCrossJoin(metadata, context, accessNode1, accessNode2)) {
+                    	//if (hasJoinCriteria) {
+                    		//a cross join would still be a good idea given that a dependent join can be used
+                    	//}
                     	continue;
                     }                    
                     
@@ -277,7 +279,7 @@
                     JoinType joinType = joinCriteria.isEmpty()?JoinType.JOIN_CROSS:JoinType.JOIN_INNER;
                     
                     //try to push to the source
-                    if (RuleRaiseAccess.canRaiseOverJoin(toTest, metadata, capFinder, joinCriteria, joinType) == null) {
+                    if (RuleRaiseAccess.canRaiseOverJoin(toTest, metadata, capFinder, joinCriteria, joinType, null) == null) {
                         continue;
                     }
                     
@@ -521,7 +523,7 @@
      * @param metadata
      * @return
      */
-    Object[] findBestJoinOrder(JoinRegion region, QueryMetadataInterface metadata) {
+    Object[] findBestJoinOrder(JoinRegion region, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
         int regionCount = region.getJoinSourceNodes().size();
         
         List<Integer> orderList = new ArrayList<Integer>(regionCount);

Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -386,7 +386,7 @@
         projectPlanNode.setProperty(NodeConstants.Info.PROJECT_COLS, projectedViewSymbols);
         projectPlanNode.addGroup(group);
         if (pushdown) {
-        	while (RuleRaiseAccess.raiseAccessNode(root, originalNode, metadata, capFinder, true) != null) {
+        	while (RuleRaiseAccess.raiseAccessNode(root, originalNode, metadata, capFinder, true, null) != null) {
         		//continue to raise
         	}
         }
@@ -487,7 +487,7 @@
     		
             //check for push down
             if (stageGroup.getFirstChild().getType() == NodeConstants.Types.ACCESS 
-                            && RuleRaiseAccess.canRaiseOverGroupBy(stageGroup, stageGroup.getFirstChild(), aggregates, metadata, capFinder)) {
+                            && RuleRaiseAccess.canRaiseOverGroupBy(stageGroup, stageGroup.getFirstChild(), aggregates, metadata, capFinder, null)) {
                 RuleRaiseAccess.performRaise(null, stageGroup.getFirstChild(), stageGroup);
                 if (stagedGroupingSymbols.isEmpty()) {
                     RuleRaiseAccess.performRaise(null, stageGroup.getParent(), stageGroup.getParent().getParent());

Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -94,7 +94,7 @@
 	            	continue;
 	            }
 	            
-	            PlanNode sourceNode = findOriginatingNode(metadata, capFinder, critNode);
+	            PlanNode sourceNode = findOriginatingNode(metadata, capFinder, critNode, analysisRecord);
 	            
 	            if(sourceNode == null) {
                     deadNodes.add(critNode);
@@ -137,7 +137,7 @@
 	}
 
 	private PlanNode findOriginatingNode(QueryMetadataInterface metadata,
-			CapabilitiesFinder capFinder, PlanNode critNode)
+			CapabilitiesFinder capFinder, PlanNode critNode, AnalysisRecord record)
 			throws TeiidComponentException, QueryMetadataException {
 		if (critNode.getGroups().isEmpty()) {
 	        //check to see if pushing may impact cardinality
@@ -146,7 +146,7 @@
 	        	return groupNode;
 	        }
 
-			Object modelId = getSubqueryModelId(metadata, capFinder, critNode);
+			Object modelId = getSubqueryModelId(metadata, capFinder, critNode, record);
 			if (modelId != null) {
 				for (PlanNode node : NodeEditor.findAllNodes(critNode, NodeConstants.Types.SOURCE)) {
 		            GroupSymbol group = node.getGroups().iterator().next();
@@ -161,11 +161,11 @@
 	}
 
 	private Object getSubqueryModelId(QueryMetadataInterface metadata,
-			CapabilitiesFinder capFinder, PlanNode critNode)
+			CapabilitiesFinder capFinder, PlanNode critNode, AnalysisRecord record)
 			throws TeiidComponentException, QueryMetadataException {
 		Object modelId = null;
 		for (SubqueryContainer subqueryContainer : critNode.getSubqueryContainers()) {
-			Object validId = CriteriaCapabilityValidatorVisitor.validateSubqueryPushdown(subqueryContainer, null, metadata, capFinder);
+			Object validId = CriteriaCapabilityValidatorVisitor.validateSubqueryPushdown(subqueryContainer, null, metadata, capFinder, record);
 			if (validId == null) {
 				return null;
 			}
@@ -282,7 +282,7 @@
 			// Look for situations where we don't allow SELECT to be pushed
 			if(currentNode.getType() == NodeConstants.Types.ACCESS) {
                 try {
-                    if (!RuleRaiseAccess.canRaiseOverSelect(currentNode, metadata, capFinder, critNode)) {
+                    if (!RuleRaiseAccess.canRaiseOverSelect(currentNode, metadata, capFinder, critNode, null)) {
                         return currentNode;
                     }
                     

Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -73,7 +73,7 @@
             raisedNode = false;
 
             for (PlanNode accessNode : NodeEditor.findAllNodes(plan, NodeConstants.Types.ACCESS)) {
-                PlanNode newRoot = raiseAccessNode(plan, accessNode, metadata, capFinder, afterJoinPlanning);
+                PlanNode newRoot = raiseAccessNode(plan, accessNode, metadata, capFinder, afterJoinPlanning, analysisRecord);
                 if(newRoot != null) {
                     raisedNode = true;
                     plan = newRoot;
@@ -87,7 +87,8 @@
     /**
      * @return null if nothing changed, and a new plan root if something changed
      */
-    static PlanNode raiseAccessNode(PlanNode rootNode, PlanNode accessNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, boolean afterJoinPlanning) 
+    static PlanNode raiseAccessNode(PlanNode rootNode, PlanNode accessNode, QueryMetadataInterface metadata, 
+    		CapabilitiesFinder capFinder, boolean afterJoinPlanning, AnalysisRecord record) 
     throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
         
         PlanNode parentNode = accessNode.getParent();
@@ -103,7 +104,7 @@
         switch(parentNode.getType()) {
             case NodeConstants.Types.JOIN:
             {
-                modelID = canRaiseOverJoin(modelID, parentNode, metadata, capFinder, afterJoinPlanning);
+                modelID = canRaiseOverJoin(modelID, parentNode, metadata, capFinder, afterJoinPlanning, record);
                 if(modelID != null) {
                     raiseAccessOverJoin(parentNode, modelID, true);                    
                     return rootNode;
@@ -117,7 +118,7 @@
                 
                 for (int i = 0; i < projectCols.size(); i++) {
                     SingleElementSymbol symbol = (SingleElementSymbol)projectCols.get(i);
-                    if(! canPushSymbol(symbol, true, modelID, metadata, capFinder)) {
+                    if(! canPushSymbol(symbol, true, modelID, metadata, capFinder, record)) {
                         return null;
                     } 
                 }
@@ -138,10 +139,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$
                 	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$
                 	return null;
                 }
                 
@@ -149,7 +153,7 @@
             }
             case NodeConstants.Types.SORT:
             {         
-                if (canRaiseOverSort(accessNode, metadata, capFinder, parentNode)) {
+                if (canRaiseOverSort(accessNode, metadata, capFinder, parentNode, record)) {
                     return performRaise(rootNode, accessNode, parentNode);
                 }
                 return null;
@@ -157,7 +161,7 @@
             case NodeConstants.Types.GROUP:            
             {                
                 Set<AggregateSymbol> aggregates = RulePushAggregates.collectAggregates(parentNode);
-                if (canRaiseOverGroupBy(parentNode, accessNode, aggregates, metadata, capFinder)) {
+                if (canRaiseOverGroupBy(parentNode, accessNode, aggregates, metadata, capFinder, record)) {
                     return performRaise(rootNode, accessNode, parentNode);
                 }
                 return null;
@@ -180,7 +184,7 @@
             	if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
             		return null;
             	}
-            	if (canRaiseOverSelect(accessNode, metadata, capFinder, parentNode)) {
+            	if (canRaiseOverSelect(accessNode, metadata, capFinder, parentNode, record)) {
                     RulePushSelectCriteria.satisfyAccessPatterns(parentNode, accessNode);
                     return performRaise(rootNode, accessNode, parentNode);                      
             	}
@@ -212,7 +216,7 @@
 				}
     			PlanNode newParent = grandParent.getParent();
 				//TODO: use costing or heuristics instead of always raising
-    			PlanNode newRoot = raiseAccessNode(rootNode, accessNode, metadata, capFinder, afterJoinPlanning);
+    			PlanNode newRoot = raiseAccessNode(rootNode, accessNode, metadata, capFinder, afterJoinPlanning, record);
     			if (newRoot == null) {
 					//return the tree to its original state
     				parentNode.addFirstChild(accessNode);
@@ -291,7 +295,7 @@
                                          PlanNode accessNode,
                                          Collection<? extends SingleElementSymbol> aggregates,
                                          QueryMetadataInterface metadata,
-                                         CapabilitiesFinder capFinder) throws QueryMetadataException,
+                                         CapabilitiesFinder capFinder, AnalysisRecord record) throws QueryMetadataException,
                                                         TeiidComponentException {
         Object modelID = getModelIDFromAccess(accessNode, metadata);
         if(modelID == null) {
@@ -299,29 +303,36 @@
         }
         List<SingleElementSymbol> groupCols = (List<SingleElementSymbol>)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$
             return false;
         }
         if (groupCols != null) {
             for (SingleElementSymbol singleElementSymbol : groupCols) {
-                if (!canPushSymbol(singleElementSymbol, false, modelID, metadata, capFinder)) {
+                if (!canPushSymbol(singleElementSymbol, false, modelID, metadata, capFinder, record)) {
                     return false;
                 }
             }
         }
         if (aggregates != null) {
             for (SingleElementSymbol aggregateSymbol : aggregates) {
-                if(! CriteriaCapabilityValidatorVisitor.canPushLanguageObject(aggregateSymbol, modelID, metadata, capFinder)) {
+                if(! CriteriaCapabilityValidatorVisitor.canPushLanguageObject(aggregateSymbol, modelID, metadata, capFinder, record)) {
                     return false;
                 }
             }
         }
         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,
                                    QueryMetadataInterface metadata,
                                    CapabilitiesFinder capFinder,
-                                   PlanNode parentNode) throws QueryMetadataException,
+                                   PlanNode parentNode, AnalysisRecord record) throws QueryMetadataException,
                                                        TeiidComponentException {
         // Find the model for this node by getting ACCESS node's model
         Object modelID = getModelIDFromAccess(accessNode, metadata);
@@ -333,7 +344,7 @@
         List<OrderByItem> sortCols = ((OrderBy)parentNode.getProperty(NodeConstants.Info.SORT_ORDER)).getOrderByItems();
         for (OrderByItem symbol : sortCols) {
             //TODO: this check shouldn't be necessary, since the order by is not introducing new expressions
-            if(! canPushSymbol(symbol.getSymbol(), true, modelID, metadata, capFinder)) {
+            if(! canPushSymbol(symbol.getSymbol(), true, modelID, metadata, capFinder, record)) {
                 return false;
             }
             boolean supportsNullOrdering = CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_NULL_ORDERING, modelID, metadata, capFinder);
@@ -407,7 +418,7 @@
     static boolean canRaiseOverSelect(PlanNode accessNode,
                                         QueryMetadataInterface metadata,
                                         CapabilitiesFinder capFinder,
-                                        PlanNode parentNode) throws QueryMetadataException,
+                                        PlanNode parentNode, AnalysisRecord record) throws QueryMetadataException,
                                                             TeiidComponentException,
                                                             QueryPlannerException {
         if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_PHANTOM)) {
@@ -422,6 +433,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$
         	return false;
         }
         
@@ -433,7 +445,7 @@
         
         Criteria crit = (Criteria) parentNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
         
-        if(!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, modelID, metadata, capFinder) ) { 
+        if(!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, modelID, metadata, capFinder, record) ) { 
             return false;                        
         } 
         
@@ -456,13 +468,14 @@
      * @throws QueryMetadataException
      * @since 4.1.2
      */
-    private static boolean canPushSymbol(SingleElementSymbol symbol, boolean inSelectClause, Object modelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) 
+    private static boolean canPushSymbol(SingleElementSymbol symbol, boolean inSelectClause, Object modelID, 
+    		QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record) 
     throws TeiidComponentException, QueryMetadataException {
 
         Expression expr = SymbolMap.getExpression(symbol);
         
         // Do the normal checks
-        if(! CriteriaCapabilityValidatorVisitor.canPushLanguageObject(expr, modelID, metadata, capFinder)) {
+        if(! CriteriaCapabilityValidatorVisitor.canPushLanguageObject(expr, modelID, metadata, capFinder, record)) {
             return false;
         }
         
@@ -499,7 +512,8 @@
      * @return The modelID if the raise can proceed and what common model these combined
      * nodes will be sent to
      */
-	private static Object canRaiseOverJoin(Object modelId, PlanNode joinNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, boolean afterJoinPlanning) 
+	private static Object canRaiseOverJoin(Object modelId, PlanNode joinNode, QueryMetadataInterface metadata, 
+			CapabilitiesFinder capFinder, boolean afterJoinPlanning, AnalysisRecord record) 
 		throws QueryMetadataException, TeiidComponentException {
 		
         List crits = (List) joinNode.getProperty(NodeConstants.Info.JOIN_CRITERIA);
@@ -536,14 +550,14 @@
 			}
 		}
         
-        return canRaiseOverJoin(joinNode.getChildren(), metadata, capFinder, crits, type);		
+        return canRaiseOverJoin(joinNode.getChildren(), metadata, capFinder, crits, type, record);		
 	}
 
     static Object canRaiseOverJoin(List<PlanNode> children,
                                            QueryMetadataInterface metadata,
                                            CapabilitiesFinder capFinder,
                                            List<Criteria> crits,
-                                           JoinType type) throws QueryMetadataException,
+                                           JoinType type, AnalysisRecord record) throws QueryMetadataException,
                                                          TeiidComponentException {
         //we only want to consider binary joins
         if (children.size() != 2) {
@@ -602,7 +616,7 @@
 					List<Object> rightIds = null;
 					GroupSymbol leftGroup = null;
 					for (Criteria crit : crits) {
-				        if (!isSupportedJoinCriteria(sjc, crit, accessModelID, metadata, capFinder)) {
+				        if (!isSupportedJoinCriteria(sjc, crit, accessModelID, metadata, capFinder, record)) {
 				        	return null;
 				        }
 			        	if (sjc != SupportedJoinCriteria.KEY) {
@@ -663,9 +677,10 @@
     /**
      * Checks criteria one predicate at a time.  Only tests up to the equi restriction.
      */
-    static boolean isSupportedJoinCriteria(SupportedJoinCriteria sjc, Criteria crit, Object accessModelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) 
+    static boolean isSupportedJoinCriteria(SupportedJoinCriteria sjc, Criteria crit, Object accessModelID, 
+    		QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record) 
     throws QueryMetadataException, TeiidComponentException {
-    	if(!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, accessModelID, metadata, capFinder) ) { 
+    	if(!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, accessModelID, metadata, capFinder, record) ) { 
             return false;                        
         } 
         if (sjc == SupportedJoinCriteria.ANY) {

Modified: branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCalculateCostUtil.java
===================================================================
--- branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCalculateCostUtil.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCalculateCostUtil.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -24,6 +24,9 @@
 
 import static org.junit.Assert.*;
 
+import java.util.Arrays;
+
+import org.junit.Ignore;
 import org.junit.Test;
 import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.core.TeiidComponentException;
@@ -35,7 +38,6 @@
 import org.teiid.query.optimizer.relational.plantree.NodeConstants;
 import org.teiid.query.optimizer.relational.plantree.NodeFactory;
 import org.teiid.query.optimizer.relational.plantree.PlanNode;
-import org.teiid.query.optimizer.relational.rules.NewCalculateCostUtil;
 import org.teiid.query.parser.QueryParser;
 import org.teiid.query.processor.TestVirtualDepJoin;
 import org.teiid.query.processor.relational.RelationalPlan;
@@ -47,7 +49,7 @@
 import org.teiid.query.unittest.FakeMetadataObject;
 import org.teiid.query.util.CommandContext;
 
-
+ at SuppressWarnings("nls")
 public class TestCalculateCostUtil {
 
     // =====================================================================
@@ -303,6 +305,21 @@
         float cost = NewCalculateCostUtil.computeCostForTree(joinNode, metadata);
         assertTrue(cost == NewCalculateCostUtil.UNKNOWN_VALUE);
     }
+    
+    @Ignore("this logic needs to be refined to work better")
+    @Test public void testEstimateJoinNodeCostOneUnknown() throws Exception {
+        QueryMetadataInterface metadata = FakeMetadataFactory.example4();
+        PlanNode joinNode = helpGetJoinNode(NewCalculateCostUtil.UNKNOWN_VALUE, 500, JoinType.JOIN_INNER);
+        joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, Arrays.asList(helpGetCriteria("pm1.g1.e1 = pm1.g2.e1", metadata)));
+        float cost = NewCalculateCostUtil.computeCostForTree(joinNode, metadata);
+        assertEquals(10000, cost, 0);
+    }
+    
+    @Test public void testEstimateNdvPostJoin() throws Exception {
+    	String query = "SELECT account FROM US.Accounts, Europe.CustAccts, CustomerMaster.Customers where account + accid + CustomerMaster.Customers.id = 1000000"; //$NON-NLS-1$
+    	
+    	helpTestQuery(1E9f, query, new String[] {"SELECT g_0.accid FROM Europe.CustAccts AS g_0", "SELECT g_0.id FROM CustomerMaster.Customers AS g_0", "SELECT g_0.account FROM US.Accounts AS g_0"});
+    }
 
     /** 
      * cases 2159 and 2160, defect 14998
@@ -732,10 +749,17 @@
         op +  
         "SELECT id, convert(accid / 10000, long), mod(accid, 10000), convert(type, integer), amount, 'EU' from Europe.CustAccts"; //$NON-NLS-1$
         
-        RelationalPlan plan = (RelationalPlan)TestOptimizer.helpPlan(query, TestVirtualDepJoin.exampleVirtualDepJoin(), new String[] {"SELECT g_0.customer, g_0.account, g_0.txnid, g_0.txn, g_0.pennies FROM US.Accounts AS g_0 WHERE g_0.txn <> 'X'", "SELECT g_0.id, g_0.accid, g_0.type, g_0.amount FROM Europe.CustAccts AS g_0"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ //$NON-NLS-2$
+        String[] expected = new String[] {"SELECT g_0.customer, g_0.account, g_0.txnid, g_0.txn, g_0.pennies FROM US.Accounts AS g_0 WHERE g_0.txn <> 'X'", "SELECT g_0.id, g_0.accid, g_0.type, g_0.amount FROM Europe.CustAccts AS g_0"};
         
+        helpTestQuery(cost, query, expected);
+    }
+
+	private void helpTestQuery(float cost, String query, String[] expected)
+			throws TeiidComponentException, TeiidProcessingException {
+		RelationalPlan plan = (RelationalPlan)TestOptimizer.helpPlan(query, TestVirtualDepJoin.exampleVirtualDepJoin(), expected, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ //$NON-NLS-2$
+        
         assertEquals(cost, plan.getRootNode().getEstimateNodeCardinality());
-    }
+	}
     
     @Test public void testUnion() throws Exception {
     	helpTestSetOp("UNION ", 1375000.0f); //$NON-NLS-1$

Modified: branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCriteriaCapabilityValidatorVisitor.java
===================================================================
--- branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCriteriaCapabilityValidatorVisitor.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCriteriaCapabilityValidatorVisitor.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -51,7 +51,7 @@
             
             QueryResolver.resolveCriteria(criteria, metadata);
                         
-            assertEquals("Got incorrect isValid flag", isValid, CriteriaCapabilityValidatorVisitor.canPushLanguageObject(criteria, modelID, metadata, capFinder)); //$NON-NLS-1$
+            assertEquals("Got incorrect isValid flag", isValid, CriteriaCapabilityValidatorVisitor.canPushLanguageObject(criteria, modelID, metadata, capFinder, null)); //$NON-NLS-1$
         } catch(QueryMetadataException e) {
         	if (!expectException) {
         		throw new RuntimeException(e);
@@ -68,7 +68,7 @@
             
             QueryResolver.resolveCommand(command, metadata);
                         
-            assertEquals("Got incorrect isValid flag", isValid, CriteriaCapabilityValidatorVisitor.canPushLanguageObject(command, modelID, metadata, capFinder)); //$NON-NLS-1$
+            assertEquals("Got incorrect isValid flag", isValid, CriteriaCapabilityValidatorVisitor.canPushLanguageObject(command, modelID, metadata, capFinder, null)); //$NON-NLS-1$
         } catch(QueryMetadataException e) {
         	if (!expectException) {
         		throw new RuntimeException(e);

Modified: branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java
===================================================================
--- branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java	2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java	2010-09-22 21:14:19 UTC (rev 2597)
@@ -213,9 +213,7 @@
         null,
         null, 
         joinCriteria, 
-        expectedMadeDependent);        
-
-
+        expectedMadeDependent, null, null);        
     }
 
     /**
@@ -253,7 +251,7 @@
                                                         Criteria atomicRequestCrit2a,  //optional
                                                         Collection atomicJoinCriteria2,  //optional
                                                         Collection joinCriteria, 
-                                                        int expectedMadeDependent) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
+                                                        int expectedMadeDependent, Number expectedCost1, Number expectedCost2) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
 //EXAMPLE:
 //    Project(groups=[])
 //      Join(groups=[], props={21=joinCriteria, 23=true, 22=INNER JOIN})
@@ -407,6 +405,10 @@
         Float cost2 = (Float)accessNode2.getProperty(NodeConstants.Info.EST_CARDINALITY);
         assertNotNull(cost2);
         assertNotNull(cost1);
+        if (expectedCost1 != null) {
+        	assertEquals(expectedCost1.longValue(), cost1.longValue());
+        	assertEquals(expectedCost2.longValue(), cost2.longValue());
+        }
     }    
     
     // ################################## ACTUAL TESTS ################################
@@ -574,9 +576,9 @@
          atomicCrit2a, 
          atomicJoinCrits2,
          crits, 
-         expected);        
+         expected, -1, 57734);        
     }
-
+    
     /**
      * Tests that heuristics will take cardinality of a group into account when 
      * making a dependent join.
@@ -1064,7 +1066,7 @@
          atomicCrit2a, 
          atomicJoinCrits2,
          crits, 
-         expected);        
+         expected, 1000, 1);        
     }    
 
     public void testCardinalityWithAtomicCrossJoin() throws Exception {
@@ -1110,7 +1112,7 @@
          atomicCrit2a, 
          atomicJoinCrits2,
          crits, 
-         expected);        
+         expected, 1000, 1E5);        
     } 
     
     public void testCardinalityWithAtomicCrossJoin2() throws Exception {
@@ -1156,7 +1158,7 @@
          atomicCrit2a, 
          atomicJoinCrits2,
          crits, 
-         expected);        
+         expected, 1000, 9999899648l);        
     }     
 
     // ################################## TEST SUITE ################################



More information about the teiid-commits mailing list