[teiid-commits] teiid SVN: r3008 - in trunk: engine/src/main/java/org/teiid/query/eval and 11 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Fri Mar 18 14:50:33 EDT 2011


Author: shawkins
Date: 2011-03-18 14:50:32 -0400 (Fri, 18 Mar 2011)
New Revision: 3008

Modified:
   trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java
   trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.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/NewCalculateCostUtil.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java
   trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
   trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/JoinType.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
   trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java
   trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
   trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/TestExistsCriteriaImpl.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
   trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java
   trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
   trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java
Log:
TEIID-1497 adding a merge join hint to in/exists subqueries

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -349,8 +349,12 @@
         return result;
     }
 
-    Exists translate(ExistsCriteria criteria) {
-        return new Exists(translate(criteria.getCommand()));
+    Condition translate(ExistsCriteria criteria) {
+        Exists exists = new Exists(translate(criteria.getCommand()));
+        if (criteria.isNegated()) {
+        	return new Not(exists);
+        }
+        return exists;
     }
 
     IsNull translate(IsNullCriteria criteria) {

Modified: trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -588,9 +588,9 @@
 			throw new ExpressionEvaluationException(e, e.getMessage());
 		}
         if(valueIter.hasNext()) {
-            return true;
+            return !criteria.isNegated();
         }
-        return false;
+        return criteria.isNegated();
     }
     
 	public Object evaluate(Expression expression, List<?> tuple)

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	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -327,6 +327,11 @@
             return;
         }
         
+        if (crit.isNegated() && !this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
+        	markInvalid(crit, "Negation is not supported by source"); //$NON-NLS-1$
+        	return;
+        }
+        
         try {
 			if (validateSubqueryPushdown(crit, modelID, metadata, capFinder, analysisRecord) == null) {
 				if (crit.getCommand().getCorrelatedReferences() == null) {

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -602,7 +602,7 @@
             return;
         }
 
-        float cardinality = getNDVEstimate(node, metadata, childCost, expressions, false);
+        float cardinality = getNDVEstimate(node, metadata, childCost, expressions, true);
         setCardinalityEstimate(node, cardinality, true, metadata);
     }
 
@@ -1283,6 +1283,8 @@
 				ndv = cardinality;
 			} else if (useCardinalityIfUnknown) {
 				ndv = cardinality/2; 
+			} else {
+				return UNKNOWN_VALUE;
 			}
 		}
 		return Math.max(1, ndv);

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	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -33,6 +33,8 @@
 
 import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.api.exception.query.QueryPlannerException;
+import org.teiid.client.plan.Annotation;
+import org.teiid.client.plan.Annotation.Priority;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.id.IDGenerator;
 import org.teiid.query.analysis.AnalysisRecord;
@@ -119,6 +121,7 @@
 		public List<Criteria> nonEquiJoinCriteria = new LinkedList<Criteria>();
 		public Criteria additionalCritieria;
 		public Class<?> type;
+		public boolean mergeJoin;
 	}
 
 	private IDGenerator idGenerator;
@@ -143,7 +146,7 @@
 
         // Find strings of criteria and merge them, removing duplicates
         List<PlanNode> criteriaChains = new ArrayList<PlanNode>();
-        findCriteriaChains(plan, criteriaChains);
+        findCriteriaChains(plan, criteriaChains, analysisRecord);
         
         // Merge chains
         for (PlanNode critNode : criteriaChains) {
@@ -158,7 +161,7 @@
      * @param node Root node to search
      * @param foundNodes Roots of criteria chains
      */
-     void findCriteriaChains(PlanNode root, List<PlanNode> foundNodes)
+     void findCriteriaChains(PlanNode root, List<PlanNode> foundNodes, AnalysisRecord analysisRecord)
         throws QueryPlannerException, TeiidComponentException {
 
         PlanNode recurseRoot = root;
@@ -167,7 +170,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 = planSemiJoin(recurseRoot, root);
+            	recurseRoot = planMergeJoin(recurseRoot, root, analysisRecord);
             	if (root.getChildCount() == 0) {
             		root = recurseRoot.getFirstChild();
             		if (root.getType() != NodeConstants.Types.SELECT) {
@@ -186,7 +189,7 @@
         
         if (recurseRoot.getType() != NodeConstants.Types.ACCESS) {
             for (PlanNode child : recurseRoot.getChildren()) {
-                findCriteriaChains(child, foundNodes);
+                findCriteriaChains(child, foundNodes, analysisRecord);
             }
         }
     }
@@ -242,24 +245,24 @@
      * 
      * TODO: it would be good to have a hint to force
      */
-	private PlanNode planSemiJoin(PlanNode current, PlanNode root) throws QueryMetadataException,
+	private PlanNode planMergeJoin(PlanNode current, PlanNode root, AnalysisRecord analysisRecord) throws QueryMetadataException,
 			TeiidComponentException {
-		float sourceCost = NewCalculateCostUtil.computeCostForTree(current, metadata);
-		if (sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE 
-				&& sourceCost < RuleChooseDependent.DEFAULT_INDEPENDENT_CARDINALITY) {
-			//TODO: see if a dependent join applies
-			return current;
-		}
+		float sourceCost = NewCalculateCostUtil.computeCostForTree(current.getFirstChild(), metadata);
 		Criteria crit = (Criteria)current.getProperty(NodeConstants.Info.SELECT_CRITERIA);
 		
 		PlannedResult plannedResult = findSubquery(crit);
 		if (plannedResult.query == null) {
 			return current;
 		}
+		if (sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE 
+				&& sourceCost < RuleChooseDependent.DEFAULT_INDEPENDENT_CARDINALITY && !plannedResult.mergeJoin) {
+			//TODO: see if a dependent join applies the other direction
+			return current;
+		}
 		
 		RelationalPlan originalPlan = (RelationalPlan)plannedResult.query.getProcessorPlan();
         Number originalCardinality = originalPlan.getRootNode().getEstimateNodeCardinality();
-        if (originalCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE) {
+        if (!plannedResult.mergeJoin && originalCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE) {
             //TODO: this check isn't really accurate - exists and scalarsubqueries will always have cardinality 2/1
         	//if it's currently unknown, removing criteria won't make it any better
         	return current;
@@ -268,6 +271,9 @@
         Collection<GroupSymbol> leftGroups = FrameUtil.findJoinSourceNode(current).getGroups();
 
 		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$
+			}
 			return current;
 		}
 		
@@ -283,18 +289,26 @@
 			List<SingleElementSymbol> projectedSymbols = LanguageObject.Util.deepClone(plannedResult.query.getProjectedSymbols(), SingleElementSymbol.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 mege join"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
 			RelationalPlan subPlan = (RelationalPlan)QueryOptimizer.optimizePlan(plannedResult.query, metadata, idGenerator, capFinder, analysisRecord, context);
-            Number planCardinality = subPlan.getRootNode().getEstimateNodeCardinality();
+			Number planCardinality = subPlan.getRootNode().getEstimateNodeCardinality();
             
-            if (planCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE 
-            		|| planCardinality.floatValue() > 10000000
-            		|| (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE && planCardinality.floatValue() > 1000)
-            		|| (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
-            	return current;
-            }
+			if (!plannedResult.mergeJoin) {
+				//if we don't have a specific hint, then use costing
+	            if (planCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE 
+	            		|| planCardinality.floatValue() > 10000000
+	            		|| (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE && planCardinality.floatValue() > 1000)
+	            		|| (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$
+	    			}
+	            	return current;
+	            }
+			}
             
-            //TODO: don't allow if too large
             PlanNode semiJoin = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
             semiJoin.addGroups(current.getGroups());
             semiJoin.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE);
@@ -336,6 +350,7 @@
 			SubquerySetCriteria ssc = (SubquerySetCriteria)crit;
 			result.not ^= ssc.isNegated();
 			result.type = crit.getClass();
+			result.mergeJoin = ssc.isMergeJoin();
 			crit = new SubqueryCompareCriteria(ssc.getExpression(), ssc.getCommand(), SubqueryCompareCriteria.EQ, SubqueryCompareCriteria.SOME);
 		} else if (crit instanceof CompareCriteria) {
 			//convert to the quantified form
@@ -343,6 +358,7 @@
 			if (cc.getRightExpression() instanceof ScalarSubquery) {
 				ScalarSubquery ss = (ScalarSubquery)cc.getRightExpression();
 				result.type = ss.getClass();
+				//we can only use a semi-join if we know that 1 row will be present
 				if (ss.getCommand() instanceof Query) {
 					Query query = (Query)ss.getCommand();
 					if (query.getGroupBy() == null && query.hasAggregates()) {
@@ -378,8 +394,10 @@
 				return result;
 			} 
 			result.type = crit.getClass();
+			result.not = exists.isNegated();
 			//the correlations can only be in where (if no group by or aggregates) or having
 			result.query = (Query)exists.getCommand();
+			result.mergeJoin = exists.isMergeJoin();
 		}
 		return result;
 	}
@@ -466,8 +484,6 @@
 		}
 		
 		if (plannedResult.leftExpressions.isEmpty()) {
-			//there's no equi-join
-			//TODO: if there are correlations a "cross" join may still be preferable 
 			return false;
 		}
 		

Modified: trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -39,6 +39,7 @@
 import org.teiid.query.sql.lang.QueryCommand;
 import org.teiid.query.sql.lang.SetQuery;
 import org.teiid.query.sql.proc.CriteriaSelector;
+import org.teiid.query.sql.visitor.SQLStringVisitor;
 
 public class SQLParserUtil {
 	
@@ -165,8 +166,18 @@
             }        
         }
     }
-
-	private String getComment(Token t) {
+    
+    boolean isMergeJoin(Token t) {
+    	String[] parts = getComment(t).split("\\s"); //$NON-NLS-1$
+    	for (int i = 0; i < parts.length; i++) {
+            if (parts[i].equalsIgnoreCase(SQLStringVisitor.MJ)) {
+                return true;
+            }        
+        }
+    	return false;
+    }
+    
+	String getComment(Token t) {
 		Token optToken = t.specialToken;
         if (optToken == null) { 
             return ""; //$NON-NLS-1$

Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -1134,7 +1134,7 @@
 			}
 		    rewriteSubqueryContainer((SubqueryContainer)criteria, true);
 			if (!RelationalNodeUtil.shouldExecute(exists.getCommand(), false, true)) {
-            	return FALSE_CRITERIA;
+            	return exists.isNegated()?TRUE_CRITERIA:FALSE_CRITERIA;
             }
 		    if (exists.getCommand().getProcessorPlan() == null) {
 	            addImplicitLimit(exists, 1);

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -27,6 +27,7 @@
 import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.core.util.HashCodeUtil;
 import org.teiid.query.sql.LanguageVisitor;
+import org.teiid.query.sql.lang.PredicateCriteria.Negatable;
 import org.teiid.query.sql.symbol.ContextReference;
 import org.teiid.query.sql.symbol.Expression;
 
@@ -37,13 +38,15 @@
  * "EXISTS (Select EmployeeID FROM Employees WHERE EmployeeName = 'Smith')".
  */
 public class ExistsCriteria extends PredicateCriteria
-implements SubqueryContainer<QueryCommand>, ContextReference {
+implements SubqueryContainer<QueryCommand>, ContextReference, Negatable {
 	
 	private static AtomicInteger ID = new AtomicInteger();
 
     private QueryCommand command;
     private String id = "$ec/id" + ID.getAndIncrement(); //$NON-NLS-1$
     private boolean shouldEvaluate;
+    private boolean mergeJoin;
+    private boolean negated;
 
     /**
      * Default constructor
@@ -51,6 +54,14 @@
     public ExistsCriteria() {
         super();
     }
+    
+    public void setMergeJoin(boolean semiJoin) {
+		this.mergeJoin = semiJoin;
+	}
+    
+    public boolean isMergeJoin() {
+		return mergeJoin;
+	}
 
     public ExistsCriteria(QueryCommand subqueryCommand){
         this.command = subqueryCommand;
@@ -104,7 +115,6 @@
      * @return True if equal
      */
     public boolean equals(Object obj) {
-        // Use super.equals() to check obvious stuff and variable
         if(obj == this) {
             return true;
         }
@@ -112,8 +122,12 @@
         if(!(obj instanceof ExistsCriteria)) {
             return false;
         }
+        
+        ExistsCriteria other = (ExistsCriteria)obj;
 
-        return EquivalenceUtil.areEqual(getCommand(), ((ExistsCriteria)obj).getCommand());
+        return EquivalenceUtil.areEqual(getCommand(), other.getCommand()) &&
+        	this.negated == other.negated &&
+        	this.mergeJoin == other.mergeJoin;
     }
 
     /**
@@ -124,6 +138,22 @@
      * @see java.lang.Object#clone()
      */
     public Object clone() {
-        return new ExistsCriteria((QueryCommand) this.command.clone());
+        ExistsCriteria ec = new ExistsCriteria((QueryCommand) this.command.clone());
+        ec.setMergeJoin(this.mergeJoin);
+        ec.setNegated(this.negated);
+        return ec;
     }
+    
+    public boolean isNegated() {
+		return negated;
+	}
+    
+    public void setNegated(boolean negated) {
+		this.negated = negated;
+	}
+
+	@Override
+	public void negate() {
+		this.negated = !this.negated;
+	}
 }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/JoinType.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/JoinType.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/JoinType.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -22,7 +22,8 @@
 
 package org.teiid.query.sql.lang;
 
-import org.teiid.query.sql.*;
+import org.teiid.query.sql.LanguageObject;
+import org.teiid.query.sql.LanguageVisitor;
 import org.teiid.query.sql.visitor.SQLStringVisitor;
 
 /**
@@ -102,10 +103,6 @@
 		return outer; 	
 	}
 	
-	public boolean isSemi() {
-	    return this.equals(JOIN_ANTI_SEMI) || this.equals(JOIN_SEMI);
-	}
-
 	/**
 	 * Override Object.equals() to compare objects
 	 * @param other Other object

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -42,6 +42,7 @@
 
     private QueryCommand command;
     private String id = "$ssc/id" + ID.getAndIncrement(); //$NON-NLS-1$
+    private boolean mergeJoin;
 
     /**
      * Constructor for SubquerySetCriteria.
@@ -55,6 +56,14 @@
         setCommand(subCommand);
     }
     
+    public boolean isMergeJoin() {
+		return mergeJoin;
+	}
+    
+    public void setMergeJoin(boolean semiJoin) {
+		this.mergeJoin = semiJoin;
+	}
+    
     @Override
     public String getContextSymbol() {
     	return id;
@@ -114,12 +123,11 @@
         }
 
         SubquerySetCriteria sc = (SubquerySetCriteria)obj;
-        if (isNegated() ^ sc.isNegated()) {
-            return false;
-        }
 
-        return EquivalenceUtil.areEqual(getExpression(), sc.getExpression()) &&
-               EquivalenceUtil.areEqual(getCommand(), sc.getCommand());
+        return this.isNegated() == sc.isNegated() &&
+         	   EquivalenceUtil.areEqual(getExpression(), sc.getExpression()) &&
+               EquivalenceUtil.areEqual(getCommand(), sc.getCommand()) &&
+               this.mergeJoin == sc.mergeJoin;
     }
 
     /**
@@ -128,7 +136,7 @@
      * (see #setValueIterator setValueIterator}).
      * @return Deep copy of object
      */
-    public Object clone() {
+    public SubquerySetCriteria clone() {
         Expression copy = null;
         if(getExpression() != null) {
             copy = (Expression) getExpression().clone();
@@ -141,6 +149,7 @@
 
         SubquerySetCriteria criteriaCopy = new SubquerySetCriteria(copy, copyCommand);
         criteriaCopy.setNegated(isNegated());
+        criteriaCopy.mergeJoin = this.mergeJoin;
         return criteriaCopy;
     }
 

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -144,6 +144,7 @@
     private static final String BEGIN_HINT = "/*+"; //$NON-NLS-1$
     private static final String END_HINT = "*/"; //$NON-NLS-1$
     private static final char ID_ESCAPE_CHAR = '\"';
+	public static String MJ = "MJ"; //$NON-NLS-1$
 
     protected StringBuilder parts = new StringBuilder();
 
@@ -1066,6 +1067,14 @@
             append(SPACE);
         }
         append(IN);
+        if (obj.isMergeJoin()) {
+            append(SPACE);
+        	append(BEGIN_HINT);
+            append(SPACE);
+            append(MJ);
+            append(SPACE);
+            append(END_HINT);
+        }
         append(" ("); //$NON-NLS-1$
         visitNode(obj.getCommand());
         append(")"); //$NON-NLS-1$
@@ -1546,8 +1555,19 @@
     }
 
     public void visit( ExistsCriteria obj ) {
-        // operator and beginning of list
+    	if (obj.isNegated()) {
+            append(NOT);
+            append(SPACE);
+        }
         append(EXISTS);
+        if (obj.isMergeJoin()) {
+            append(SPACE);
+        	append(BEGIN_HINT);
+            append(SPACE);
+            append(MJ);
+            append(SPACE);
+            append(END_HINT);
+        }
         append(" ("); //$NON-NLS-1$
         visitNode(obj.getCommand());
         append(")"); //$NON-NLS-1$

Modified: trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -119,11 +119,11 @@
         }
         
         if(groupExpressions == null) {
-            if (symbol instanceof ElementSymbol) {
+            if (symbol instanceof ElementSymbol && !((ElementSymbol)symbol).isExternalReference()) {
                 handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0037", symbol), symbol); //$NON-NLS-1$
             }
         } else if(! groupExpressions.contains(symbol)) {
-            if (symbol instanceof ElementSymbol) {
+            if (symbol instanceof ElementSymbol && !((ElementSymbol)symbol).isExternalReference()) {
                 handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0038", symbol), symbol); //$NON-NLS-1$
             }
         } else {

Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2011-03-18 18:50:32 UTC (rev 3008)
@@ -2680,11 +2680,23 @@
 
 QueryCommand subquery(ParseInfo info) :
 {
+	Object[] result = null;    
+}
+{
+	result = subqueryAndHint(info)
+	{
+		return (QueryCommand)result[0];
+	} 
+}
+
+Object[] subqueryAndHint(ParseInfo info) :
+{
     QueryCommand subquery = null;
     StoredProcedure proc = null;
+    Token lparen = null;
 }
 {
-	<LPAREN>	
+	lparen = <LPAREN>
 	( subquery = queryExpression(info) | 
 	 (
 		proc = storedProcedure(info, new StoredProcedure()) //deprecated	  
@@ -2695,7 +2707,7 @@
 	)
 	<RPAREN>
 	{
-		return subquery;
+		return new Object[] {subquery, isMergeJoin(lparen)};
 	}
 }
 
@@ -2838,7 +2850,7 @@
 {
 	Expression value = null;
 	List setList = new ArrayList();
-	QueryCommand command = null;
+	Object[] command = null;
 	boolean negated = false;
 	AbstractSetCriteria criteria = null;
 }
@@ -2846,7 +2858,7 @@
 	[<NOT> {negated = true;}]
 	<IN>
 	(
-		LOOKAHEAD(subquery(info)) (command = subquery(info)) |
+		LOOKAHEAD(subquery(info)) (command = subqueryAndHint(info)) |
 		(
 			<LPAREN>
 			value = commonValueExpression(info)
@@ -2862,14 +2874,11 @@
 			<RPAREN>
 		)
 	)
-	
-
 	{
-		if(setList.size() == 1 && setList.get(0) instanceof ScalarSubquery) {
-			ScalarSubquery subqueryExpr = (ScalarSubquery) setList.get(0);
-			criteria = new SubquerySetCriteria(expression, subqueryExpr.getCommand());
-		} else if (command != null) {
-			criteria = new SubquerySetCriteria(expression, command);
+	    if (command != null) {
+			SubquerySetCriteria ssc = new SubquerySetCriteria(expression, (QueryCommand)command[0]);
+			ssc.setMergeJoin((Boolean)command[1]);
+			criteria = ssc;
 		} else {
 		    criteria = new SetCriteria(expression, setList);
 		}
@@ -2885,15 +2894,15 @@
  */
 ExistsCriteria existsCriteria(ParseInfo info) :
 {
-    ExistsCriteria existsCrit = null;
-    QueryCommand subquery = null;
+    Object[] subquery = null;
 }
 {
 	<EXISTS>
-	subquery = subquery(info)
+	subquery = subqueryAndHint(info)
 
 	{
-		existsCrit = new ExistsCriteria(subquery);
+		ExistsCriteria existsCrit = new ExistsCriteria((QueryCommand)subquery[0]);
+		existsCrit.setMergeJoin((Boolean)subquery[1]);
 	    return existsCrit;
    	}
 }

Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/TestExistsCriteriaImpl.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/TestExistsCriteriaImpl.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/TestExistsCriteriaImpl.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -23,12 +23,12 @@
 package org.teiid.dqp.internal.datamgr;
 
 
+import junit.framework.TestCase;
+
 import org.teiid.language.Exists;
+import org.teiid.language.Not;
 import org.teiid.query.sql.lang.ExistsCriteria;
 
-
-import junit.framework.TestCase;
-
 /**
  */
 public class TestExistsCriteriaImpl extends TestCase {
@@ -41,17 +41,22 @@
         super(name);
     }
 
-    public static ExistsCriteria helpExample() {
+    public static ExistsCriteria helpExample(boolean negated) {
         ExistsCriteria crit = new ExistsCriteria(TestQueryImpl.helpExample(true));
+        crit.setNegated(negated);
         return crit;
     }
     
     public static Exists example() throws Exception {
-        return (Exists)TstLanguageBridgeFactory.factory.translate(helpExample());
+        return (Exists)TstLanguageBridgeFactory.factory.translate(helpExample(false));
     }
 
     public void testGetQuery() throws Exception {
         assertNotNull(example().getSubquery());    
     }
     
+    public void testNegated() throws Exception {
+        assertTrue(TstLanguageBridgeFactory.factory.translate(helpExample(true)) instanceof Not);    
+    }
+    
 }

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -631,7 +631,7 @@
                                       null, capFinder,
                                       new String[] {"SELECT g_0.\"MONTH\" AS c_0, g_0.\"YEAR\" AS c_1 FROM msModel.\"TIME\" AS g_0 WHERE g_0.\"YEAR\" = '1999' ORDER BY c_0", //$NON-NLS-1$
                                                     "SELECT g_0.\"MONTH\" AS c_0, g_0.CITY AS c_1, SUM(g_0.SALES) AS c_2 FROM db2model.SALES AS g_0 WHERE (g_0.\"MONTH\" IN (<dependent values>)) AND (g_0.CITY IN (<dependent values>)) GROUP BY g_0.\"MONTH\", g_0.CITY ORDER BY c_0", //$NON-NLS-1$ 
-                                                    "SELECT g_0.CITY, g_0.REGION FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA')"},  //$NON-NLS-1$
+                                                    "SELECT g_0.CITY AS c_0, g_0.REGION AS c_1 FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA') ORDER BY c_0"},  //$NON-NLS-1$
                                       ComparisonMode.EXACT_COMMAND_STRING );
 
         checkNodeTypes(plan, new int[] {
@@ -679,7 +679,7 @@
                                       null, capFinder,
                                       new String[] {"SELECT g_0.\"MONTH\" AS c_0, g_0.\"YEAR\" AS c_1 FROM msModel.\"TIME\" AS g_0 WHERE g_0.\"YEAR\" = '1999' ORDER BY c_0", //$NON-NLS-1$
                                           "SELECT g_0.\"MONTH\" AS c_0, g_0.CITY AS c_1, SUM(g_0.SALES) AS c_2 FROM db2model.SALES AS g_0 WHERE (g_0.\"MONTH\" IN (<dependent values>)) AND (g_0.CITY IN (<dependent values>)) GROUP BY g_0.\"MONTH\", g_0.CITY ORDER BY c_0", //$NON-NLS-1$ 
-                                          "SELECT g_0.CITY, g_0.REGION FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA')"},  //$NON-NLS-1$
+                                          "SELECT g_0.CITY AS c_0, g_0.REGION AS c_1 FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA') ORDER BY c_0"},  //$NON-NLS-1$
                                       ComparisonMode.EXACT_COMMAND_STRING );
 
         checkNodeTypes(plan, new int[] {

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -77,6 +77,7 @@
 import org.teiid.query.resolver.TestResolver;
 import org.teiid.query.rewriter.QueryRewriter;
 import org.teiid.query.sql.lang.Command;
+import org.teiid.query.sql.lang.JoinType;
 import org.teiid.query.sql.symbol.GroupSymbol;
 import org.teiid.query.sql.visitor.GroupCollectorVisitor;
 import org.teiid.query.sql.visitor.ValueIteratorProviderCollectorVisitor;
@@ -95,6 +96,7 @@
     public interface DependentJoin {}
     public interface DependentSelectNode {}
     public interface SemiJoin {}
+    public interface AntiSemiJoin {}
     public interface DependentProjectNode {}
     public interface DupRemoveNode {}
     public interface DupRemoveSortNode {}
@@ -385,9 +387,11 @@
         Class<?> nodeType = relationalNode.getClass();
         if(nodeType.equals(JoinNode.class)) {
         	JoinStrategy strategy = ((JoinNode)relationalNode).getJoinStrategy();
-        	if (((JoinNode)relationalNode).getJoinType().isSemi()) {
+        	if (((JoinNode)relationalNode).getJoinType().equals(JoinType.JOIN_SEMI)) {
         		updateCounts(SemiJoin.class, counts, types);
-        	}
+        	} else if (((JoinNode)relationalNode).getJoinType().equals(JoinType.JOIN_ANTI_SEMI)) {
+        		updateCounts(AntiSemiJoin.class, counts, types);
+        	} 
             if (strategy instanceof NestedLoopJoinStrategy) {
                 updateCounts(NestedLoopJoinStrategy.class, counts, types);
             } else if (strategy instanceof MergeJoinStrategy) {

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -24,10 +24,13 @@
 
 import static org.teiid.query.optimizer.TestOptimizer.*;
 
+import org.junit.Ignore;
 import org.junit.Test;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
+import org.teiid.query.optimizer.TestOptimizer.AntiSemiJoin;
 import org.teiid.query.optimizer.TestOptimizer.ComparisonMode;
+import org.teiid.query.optimizer.TestOptimizer.SemiJoin;
 import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
 import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
 import org.teiid.query.optimizer.capabilities.FakeCapabilitiesFinder;
@@ -836,6 +839,103 @@
         }); 
     } 
     
+    /**
+     * This will not plan as a semi-join since the cost seems too high
+     */
+    @Test public void testNonSemiJoinExistsCosting() {
+        ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where exists (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(),  //$NON-NLS-1$
+            new String[] { "SELECT g_0.e1, g_0.e2 FROM pm1.g2 AS g_0" }); //$NON-NLS-1$
+        checkNodeTypes(plan, new int[] {
+            1,      // Access
+            0,      // DependentAccess
+            1,      // DependentSelect
+            0,      // DependentProject
+            0,      // DupRemove
+            0,      // Grouping
+            0,      // NestedLoopJoinStrategy
+            0,      // MergeJoinStrategy
+            0,      // Null
+            0,      // PlanExecution
+            1,      // Project
+            0,      // Select
+            0,      // Sort
+            0       // UnionAll
+        }); 
+    } 
+    
+    /**
+     * Same as above, but the source is much larger, so a semi-join is favorable
+     */
+    @Test public void testSemiJoinExistsCosting() {
+        ProcessorPlan plan = helpPlan("Select e1 from pm2.g2 as o where exists (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(),  //$NON-NLS-1$
+            new String[] { "SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM pm2.g2 AS g_0 ORDER BY c_0, c_1" }); //$NON-NLS-1$
+        checkNodeTypes(plan, new int[] {
+            1,      // Access
+            0,      // DependentAccess
+            0,      // DependentSelect
+            0,      // DependentProject
+            0,      // DupRemove
+            0,      // Grouping
+            0,      // NestedLoopJoinStrategy
+            1,      // MergeJoinStrategy
+            0,      // Null
+            1,      // PlanExecution
+            1,      // Project
+            0,      // Select
+            0,      // Sort
+            0       // UnionAll
+        }); 
+        checkJoinCounts(plan, 1, 0);
+    }
+    
+    @Test public void testAntiSemiJoinExistsHint() {
+        ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where not exists /*+ MJ */ (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(),  //$NON-NLS-1$
+            new String[] { "SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM pm1.g2 AS g_0 ORDER BY c_0, c_1" }); //$NON-NLS-1$
+        checkNodeTypes(plan, new int[] {
+            1,      // Access
+            0,      // DependentAccess
+            0,      // DependentSelect
+            0,      // DependentProject
+            0,      // DupRemove
+            0,      // Grouping
+            0,      // NestedLoopJoinStrategy
+            1,      // MergeJoinStrategy
+            0,      // Null
+            1,      // PlanExecution
+            1,      // Project
+            0,      // Select
+            0,      // Sort
+            0       // UnionAll
+        }); 
+        checkJoinCounts(plan, 0, 1);
+    }
+    
+    @Test public void testSemiJoinInHint() {
+        ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where e2 IN /*+ MJ */ (select count(e2) from pm3.g1 where e1 = o.e1)", FakeMetadataFactory.example4(),  //$NON-NLS-1$
+            new String[] { "SELECT g_0.e2 AS c_0, g_0.e1 AS c_1 FROM pm1.g2 AS g_0 ORDER BY c_1, c_0" }); //$NON-NLS-1$
+        checkNodeTypes(plan, new int[] {
+            1,      // Access
+            0,      // DependentAccess
+            0,      // DependentSelect
+            0,      // DependentProject
+            0,      // DupRemove
+            0,      // Grouping
+            0,      // NestedLoopJoinStrategy
+            1,      // MergeJoinStrategy
+            0,      // Null
+            1,      // PlanExecution
+            1,      // Project
+            0,      // Select
+            0,      // Sort
+            0       // UnionAll
+        }); 
+        checkJoinCounts(plan, 1, 0);
+    }
+    
+    void checkJoinCounts(ProcessorPlan plan, int semi, int antiSemi) {
+    	checkNodeTypes(plan, new int[] {semi, antiSemi}, new Class[] {SemiJoin.class, AntiSemiJoin.class});
+    }
+    
     @Test public void testNonSemiJoin() throws Exception {
         ProcessorPlan plan = helpPlan("Select x from xmltable('/a/b' passing convert('<a/>', xml) columns x integer path '@x') as t where x = (select count(e2) FROM pm1.g2)", FakeMetadataFactory.example4(),  //$NON-NLS-1$
             new String[] {}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
@@ -877,4 +977,27 @@
             new String[] { "SELECT g_0.e1 FROM pm1.g1 AS g_0 WHERE g_0.e1 <= (SELECT MAX(X.e1) FROM (SELECT e1 FROM pm2.g1) AS X)" }, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
         checkNodeTypes(plan, FULL_PUSHDOWN); 
     }
+    
+    @Ignore
+    @Test public void testUncorrelatedSet() {
+        ProcessorPlan plan = helpPlan("Select e1 from pm1.g1 where e1 in (select e1 FROM pm2.g1)", FakeMetadataFactory.example1Cached(),  //$NON-NLS-1$
+            new String[] { "SELECT e1, pm1.g1.e2 FROM pm1.g1" }); //$NON-NLS-1$
+        checkNodeTypes(plan, new int[] {
+            1,      // Access
+            0,      // DependentAccess
+            1,      // DependentSelect
+            0,      // DependentProject
+            0,      // DupRemove
+            0,      // Grouping
+            0,      // NestedLoopJoinStrategy
+            0,      // MergeJoinStrategy
+            0,      // Null
+            0,      // PlanExecution
+            1,      // Project
+            0,      // Select
+            0,      // Sort
+            0       // UnionAll
+        }); 
+    }
+
 }

Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -22,7 +22,7 @@
 
 package org.teiid.query.parser;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -1144,4 +1144,16 @@
         TestParser.helpTest(sql, "/*+ cache */ ? = EXEC proc()", sp);         //$NON-NLS-1$
     }
     
+    @Test public void testSemiJoinHint() {
+        String sql = "SELECT e1 FROM m.g2 WHERE EXISTS /*+ MJ */ (SELECT e1 FROM m.g1)"; //$NON-NLS-1$
+        Query q = TestParser.exampleExists(true);
+        TestParser.helpTest(sql, "SELECT e1 FROM m.g2 WHERE EXISTS /*+ MJ */ (SELECT e1 FROM m.g1)", q);         //$NON-NLS-1$
+    }
+    
+    @Test public void testSemiJoinHint1() {
+        String sql = "SELECT a FROM db.g WHERE b IN /*+ MJ */ (SELECT a FROM db.g WHERE a2 = 5)"; //$NON-NLS-1$
+        Query q = TestParser.exampleIn(true);
+        TestParser.helpTest(sql, "SELECT a FROM db.g WHERE b IN /*+ MJ */ (SELECT a FROM db.g WHERE a2 = 5)", q);         //$NON-NLS-1$
+    }
+    
 }

Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -4955,7 +4955,15 @@
      
     @Test public void testSubquerySetCriteria0() { 
         //test wrap up command with subquerySetCriteria
-        GroupSymbol g = new GroupSymbol("db.g"); //$NON-NLS-1$
+        Query outer = exampleIn(false);
+                     
+        helpTest("SELECT a FROM db.g WHERE b IN (SELECT a FROM db.g WHERE a2 = 5)", //$NON-NLS-1$
+            "SELECT a FROM db.g WHERE b IN (SELECT a FROM db.g WHERE a2 = 5)", //$NON-NLS-1$
+             outer);        
+    }
+    
+	static Query exampleIn(boolean semiJoin) {
+		GroupSymbol g = new GroupSymbol("db.g"); //$NON-NLS-1$
         From from = new From();
         from.addGroup(g);
 
@@ -4972,16 +4980,13 @@
         query.setFrom(from);
         query.setCriteria(criteria);
         SubquerySetCriteria subCrit = new SubquerySetCriteria(expr, query);
-       
+        subCrit.setMergeJoin(semiJoin);
         Query outer = new Query();
         outer.setSelect(select);
         outer.setFrom(from);
         outer.setCriteria(subCrit);
-                     
-        helpTest("SELECT a FROM db.g WHERE b IN (SELECT a FROM db.g WHERE a2 = 5)", //$NON-NLS-1$
-            "SELECT a FROM db.g WHERE b IN (SELECT a FROM db.g WHERE a2 = 5)", //$NON-NLS-1$
-             outer);        
-    }     
+		return outer;
+	}     
                
     @Test public void testSubquerySetCriteria1() { 
 
@@ -5710,7 +5715,14 @@
 
     @Test public void testExistsPredicateCriteria(){
 
-        Select s1 = new Select();
+        Query q2 = exampleExists(false);
+
+        helpTest("SELECT e1 FROM m.g2 WHERE Exists (SELECT e1 FROM m.g1)",  //$NON-NLS-1$
+                 "SELECT e1 FROM m.g2 WHERE EXISTS (SELECT e1 FROM m.g1)", //$NON-NLS-1$
+                 q2);            
+    }
+	static Query exampleExists(boolean semiJoin) {
+		Select s1 = new Select();
         s1.addSymbol(new ElementSymbol("e1")); //$NON-NLS-1$
         From f1 = new From();
         f1.addGroup(new GroupSymbol("m.g1"));        //$NON-NLS-1$
@@ -5722,16 +5734,14 @@
         s2.addSymbol(new ElementSymbol("e1")); //$NON-NLS-1$
         From f2 = new From();
         f2.addGroup(new GroupSymbol("m.g2"));        //$NON-NLS-1$
-        Criteria existsCrit = new ExistsCriteria(q1);
+        ExistsCriteria existsCrit = new ExistsCriteria(q1);
+        existsCrit.setMergeJoin(semiJoin);
         Query q2 = new Query();
         q2.setSelect(s2);
         q2.setFrom(f2);
         q2.setCriteria(existsCrit);
-
-        helpTest("SELECT e1 FROM m.g2 WHERE Exists (SELECT e1 FROM m.g1)",  //$NON-NLS-1$
-                 "SELECT e1 FROM m.g2 WHERE EXISTS (SELECT e1 FROM m.g1)", //$NON-NLS-1$
-                 q2);            
-    }
+		return q2;
+	}
     
     @Test public void testAnyQuantifierSubqueryComparePredicate(){
 

Modified: trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java	2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java	2011-03-18 18:50:32 UTC (rev 3008)
@@ -191,7 +191,7 @@
         
         ProcessorPlan plan = TestOptimizer.helpPlan("SELECT custsale.cntrycode, COUNT(*) AS numcust, SUM(c_acctbal) AS totacctbal FROM (SELECT left(C_PHONE, 2) AS cntrycode, CUSTOMER.C_ACCTBAL FROM CUSTOMER WHERE (left(C_PHONE, 2) IN ('13','31','23','29','30','18','17')) AND (CUSTOMER.C_ACCTBAL > (SELECT AVG(CUSTOMER.C_ACCTBAL) FROM CUSTOMER WHERE (CUSTOMER.C_ACCTBAL > 0.0) AND (left(C_PHONE, 2) IN ('13','31','23','29','30','18','17')))) AND (NOT (EXISTS (SELECT * FROM ORDERS WHERE O_CUSTKEY = C_CUSTKEY)))) AS custsale GROUP BY custsale.cntrycode ORDER BY custsale.cntrycode", //$NON-NLS-1$
         		METADATA, null, finder,
-        		new String[] {"SELECT v_0.c_0, COUNT(*) AS c_1, SUM(v_0.c_1) AS c_2 FROM (SELECT left(g_0.C_PHONE, 2) AS c_0, g_0.C_ACCTBAL AS c_1 FROM TPCR_Oracle_9i.CUSTOMER AS g_0 WHERE (left(g_0.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')) AND (g_0.C_ACCTBAL > (SELECT AVG(g_1.C_ACCTBAL) FROM TPCR_Oracle_9i.CUSTOMER AS g_1 WHERE (g_1.C_ACCTBAL > 0E-15) AND (left(g_1.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')))) AND (NOT (EXISTS (SELECT 1 FROM TPCR_Oracle_9i.ORDERS AS g_2 WHERE g_2.O_CUSTKEY = g_0.C_CUSTKEY)))) AS v_0 GROUP BY v_0.c_0 ORDER BY c_0 NULLS FIRST"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+        		new String[] {"SELECT v_0.c_0, COUNT(*) AS c_1, SUM(v_0.c_1) AS c_2 FROM (SELECT left(g_0.C_PHONE, 2) AS c_0, g_0.C_ACCTBAL AS c_1 FROM TPCR_Oracle_9i.CUSTOMER AS g_0 WHERE (left(g_0.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')) AND (g_0.C_ACCTBAL > (SELECT AVG(g_1.C_ACCTBAL) FROM TPCR_Oracle_9i.CUSTOMER AS g_1 WHERE (g_1.C_ACCTBAL > 0E-15) AND (left(g_1.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')))) AND (NOT EXISTS (SELECT 1 FROM TPCR_Oracle_9i.ORDERS AS g_2 WHERE g_2.O_CUSTKEY = g_0.C_CUSTKEY))) AS v_0 GROUP BY v_0.c_0 ORDER BY c_0 NULLS FIRST"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
         TestOptimizer.checkNodeTypes(plan, TestOptimizer.FULL_PUSHDOWN);
     }
     



More information about the teiid-commits mailing list