[teiid-commits] teiid SVN: r857 - in trunk: engine/src/main/java/com/metamatrix/common/buffer/impl and 14 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Mon May 4 09:21:46 EDT 2009


Author: shawkins
Date: 2009-05-04 09:21:45 -0400 (Mon, 04 May 2009)
New Revision: 857

Added:
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/PartitionedSortJoin.java
   trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestPartitionedJoinPlanning.java
Removed:
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/plantree/JoinStrategyType.java
   trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/DependentSetCriteriaCollectorVisitor.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSize1.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSize10.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSizeSameAsTupleCount.java
Modified:
   trunk/engine/src/main/java/com/metamatrix/common/buffer/IndexedTupleSource.java
   trunk/engine/src/main/java/com/metamatrix/common/buffer/impl/TupleSourceImpl.java
   trunk/engine/src/main/java/com/metamatrix/query/eval/Evaluator.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/GenerateCanonical.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/PlanToProcessConverter.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/plantree/NodeConstants.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/NewCalculateCostUtil.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleChooseDependent.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleChooseJoinStrategy.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleImplementJoinStrategy.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RulePlanJoins.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RulePlanSorts.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/BatchIterator.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/DependentValueSource.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/GroupingNode.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/JoinNode.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/JoinStrategy.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/ListNestedSortComparator.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/MergeJoinStrategy.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/NestedLoopJoinStrategy.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/SortUtility.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/SourceState.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/TupleCollector.java
   trunk/engine/src/main/java/com/metamatrix/query/sql/util/ValueIteratorSource.java
   trunk/engine/src/main/java/com/metamatrix/query/util/CommandContext.java
   trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestLimit.java
   trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestOptimizer.java
   trunk/engine/src/test/java/com/metamatrix/query/optimizer/relational/rules/TestRuleChooseDependent.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/TestProcessor.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNode.java
   trunk/test-integration/src/test/java/com/metamatrix/systemmodel/TestSystemVirtualModel.java
   trunk/test-integration/src/test/resources/partssupplier/expected/CrossReference.txt
   trunk/test-integration/src/test/resources/partssupplier/expected/ExportedKeys.txt
Log:
TEIID-545, TEIID-541, TEIID-238 peformance enhancements for unbalanced joins, non-pushed dependentset criteria, and detection of distinct join expressions.

Modified: trunk/engine/src/main/java/com/metamatrix/common/buffer/IndexedTupleSource.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/common/buffer/IndexedTupleSource.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/common/buffer/IndexedTupleSource.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -56,4 +56,7 @@
 	 * @return
 	 */
 	int getCurrentIndex();
+	
+	TupleBatch getBatch()
+    throws MetaMatrixComponentException;
 }

Modified: trunk/engine/src/main/java/com/metamatrix/common/buffer/impl/TupleSourceImpl.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/common/buffer/impl/TupleSourceImpl.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/common/buffer/impl/TupleSourceImpl.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -132,11 +132,11 @@
     }
     
     // Retrieves the necessary batch based on the currentRow
-    private TupleBatch getBatch()
+    public TupleBatch getBatch()
     throws MetaMatrixComponentException{
         TupleBatch batch = getCurrentBatch();
         if (batch != null) {
-            if (currentRow < batch.getEndRow() && currentRow > batch.getBeginRow()) {
+            if (currentRow <= batch.getEndRow() && currentRow >= batch.getBeginRow()) {
                 return batch;
             }
             unpinCurrentBatch();

Modified: trunk/engine/src/main/java/com/metamatrix/query/eval/Evaluator.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/eval/Evaluator.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/eval/Evaluator.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -24,6 +24,7 @@
 
 import java.sql.SQLException;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -74,6 +75,7 @@
 import com.metamatrix.query.sql.symbol.SearchedCaseExpression;
 import com.metamatrix.query.sql.symbol.SingleElementSymbol;
 import com.metamatrix.query.sql.util.ValueIterator;
+import com.metamatrix.query.sql.util.ValueIteratorSource;
 import com.metamatrix.query.util.CommandContext;
 import com.metamatrix.query.util.ErrorMessageKeys;
 
@@ -314,7 +316,19 @@
         	valueIter = new CollectionValueIterator(((SetCriteria)criteria).getValues());
         } else if (criteria instanceof DependentSetCriteria){
         	ContextReference ref = (ContextReference)criteria;
-        	valueIter = getContext(criteria).getValueIterator(ref);
+        	ValueIteratorSource vis = (ValueIteratorSource)getContext(criteria).getVariableContext().getGlobalValue(ref.getContextSymbol());
+        	HashSet<Object> values;
+			try {
+				values = vis.getCachedSet(ref.getValueExpression());
+			} catch (MetaMatrixProcessingException e) {
+				throw new CriteriaEvaluationException(e, e.getMessage());
+			}
+        	if (values != null) {
+        		return values.contains(leftValue);
+        	}
+        	//there are too many values to justify a linear search or holding
+        	//them in memory
+        	return true;
         } else if (criteria instanceof SubquerySetCriteria) {
         	try {
 				valueIter = evaluateSubquery((SubquerySetCriteria)criteria, tuple);

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/GenerateCanonical.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/GenerateCanonical.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/GenerateCanonical.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -30,10 +30,10 @@
 import com.metamatrix.api.exception.query.QueryPlannerException;
 import com.metamatrix.query.execution.QueryExecPlugin;
 import com.metamatrix.query.metadata.QueryMetadataInterface;
-import com.metamatrix.query.optimizer.relational.plantree.JoinStrategyType;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants;
 import com.metamatrix.query.optimizer.relational.plantree.NodeFactory;
 import com.metamatrix.query.optimizer.relational.plantree.PlanNode;
+import com.metamatrix.query.processor.relational.JoinNode.JoinStrategyType;
 import com.metamatrix.query.sql.lang.Command;
 import com.metamatrix.query.sql.lang.Criteria;
 import com.metamatrix.query.sql.lang.From;

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/PlanToProcessConverter.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/PlanToProcessConverter.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/PlanToProcessConverter.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -40,7 +40,6 @@
 import com.metamatrix.query.optimizer.capabilities.CapabilitiesFinder;
 import com.metamatrix.query.optimizer.capabilities.SourceCapabilities;
 import com.metamatrix.query.optimizer.capabilities.SourceCapabilities.Capability;
-import com.metamatrix.query.optimizer.relational.plantree.JoinStrategyType;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants;
 import com.metamatrix.query.optimizer.relational.plantree.PlanNode;
 import com.metamatrix.query.optimizer.relational.rules.CapabilitiesUtil;
@@ -55,6 +54,7 @@
 import com.metamatrix.query.processor.relational.MergeJoinStrategy;
 import com.metamatrix.query.processor.relational.NestedLoopJoinStrategy;
 import com.metamatrix.query.processor.relational.NullNode;
+import com.metamatrix.query.processor.relational.PartitionedSortJoin;
 import com.metamatrix.query.processor.relational.PlanExecutionNode;
 import com.metamatrix.query.processor.relational.ProjectIntoNode;
 import com.metamatrix.query.processor.relational.ProjectNode;
@@ -63,6 +63,7 @@
 import com.metamatrix.query.processor.relational.SelectNode;
 import com.metamatrix.query.processor.relational.SortNode;
 import com.metamatrix.query.processor.relational.UnionAllNode;
+import com.metamatrix.query.processor.relational.JoinNode.JoinStrategyType;
 import com.metamatrix.query.processor.relational.MergeJoinStrategy.SortOption;
 import com.metamatrix.query.processor.relational.SortUtility.Mode;
 import com.metamatrix.query.resolver.util.ResolverUtil;
@@ -195,11 +196,18 @@
 
                 JoinNode jnode = new JoinNode(getID());
                 jnode.setJoinType(jtype);
-                
+                jnode.setLeftDistinct(node.hasBooleanProperty(NodeConstants.Info.IS_LEFT_DISTINCT));
+                jnode.setRightDistinct(node.hasBooleanProperty(NodeConstants.Info.IS_RIGHT_DISTINCT));
                 List joinCrits = (List) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
-                
-                if(stype.equals(JoinStrategyType.MERGE)) {
-                    MergeJoinStrategy mjStrategy = new MergeJoinStrategy((SortOption)node.getProperty(NodeConstants.Info.SORT_LEFT), (SortOption)node.getProperty(NodeConstants.Info.SORT_RIGHT), false);
+                String depValueSource = (String) node.getProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE);
+                SortOption leftSort = (SortOption)node.getProperty(NodeConstants.Info.SORT_LEFT);
+                if(stype.equals(JoinStrategyType.MERGE) || stype.equals(JoinStrategyType.PARTITIONED_SORT)) {
+                	MergeJoinStrategy mjStrategy = null;
+                	if (stype.equals(JoinStrategyType.PARTITIONED_SORT)) { 
+                		mjStrategy = new PartitionedSortJoin(leftSort, (SortOption)node.getProperty(NodeConstants.Info.SORT_RIGHT));
+                	} else {
+                		mjStrategy = new MergeJoinStrategy(leftSort, (SortOption)node.getProperty(NodeConstants.Info.SORT_RIGHT), false);
+                	}
                     jnode.setJoinStrategy(mjStrategy);
                     List leftExpressions = (List) node.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS);
                     List rightExpressions = (List) node.getProperty(NodeConstants.Info.RIGHT_EXPRESSIONS);
@@ -214,7 +222,6 @@
                                
                 processNode = jnode;
                 
-                String depValueSource = (String) node.getProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE);
                 jnode.setDependentValueSource(depValueSource);
                 
 				break;

Deleted: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/plantree/JoinStrategyType.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/plantree/JoinStrategyType.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/plantree/JoinStrategyType.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -1,29 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-package com.metamatrix.query.optimizer.relational.plantree;
-
-public enum JoinStrategyType {    
-    MERGE,
-    HASH,
-    NESTED_LOOP
-}

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/plantree/NodeConstants.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/plantree/NodeConstants.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/plantree/NodeConstants.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -90,8 +90,9 @@
         SORT_LEFT,  // SortOption
         SORT_RIGHT,     // SortOption
         REMOVED_JOIN_GROUPS, //Set<GroupSymbol>
-        
         IS_OPTIONAL,          // Boolean
+        IS_LEFT_DISTINCT, 	// Boolean
+        IS_RIGHT_DISTINCT, 	// Boolean
 
         // Project node properties
         PROJECT_COLS,       // List <SingleElementSymbol>

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/NewCalculateCostUtil.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/NewCalculateCostUtil.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/NewCalculateCostUtil.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -41,10 +41,10 @@
 import com.metamatrix.query.metadata.QueryMetadataInterface;
 import com.metamatrix.query.metadata.SupportConstants;
 import com.metamatrix.query.optimizer.capabilities.CapabilitiesFinder;
-import com.metamatrix.query.optimizer.relational.plantree.JoinStrategyType;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants;
 import com.metamatrix.query.optimizer.relational.plantree.NodeEditor;
 import com.metamatrix.query.optimizer.relational.plantree.PlanNode;
+import com.metamatrix.query.processor.relational.JoinNode.JoinStrategyType;
 import com.metamatrix.query.sql.lang.AbstractSetCriteria;
 import com.metamatrix.query.sql.lang.CompareCriteria;
 import com.metamatrix.query.sql.lang.CompoundCriteria;
@@ -61,6 +61,7 @@
 import com.metamatrix.query.sql.symbol.ElementSymbol;
 import com.metamatrix.query.sql.symbol.Expression;
 import com.metamatrix.query.sql.symbol.GroupSymbol;
+import com.metamatrix.query.sql.symbol.SingleElementSymbol;
 import com.metamatrix.query.sql.util.SymbolMap;
 import com.metamatrix.query.sql.visitor.ElementCollectorVisitor;
 import com.metamatrix.query.sql.visitor.EvaluateExpressionVisitor;
@@ -786,7 +787,7 @@
         return cost;
     }
     
-    static boolean usesKey(Collection allElements, QueryMetadataInterface metadata)
+    static boolean usesKey(Collection<SingleElementSymbol> allElements, QueryMetadataInterface metadata)
         throws QueryMetadataException, MetaMatrixComponentException {
     
         if(allElements == null || allElements.size() == 0) { 
@@ -797,7 +798,11 @@
         Map groupMap = new HashMap();
         Iterator elementIter = allElements.iterator();
         while(elementIter.hasNext()) { 
-            ElementSymbol element = (ElementSymbol) elementIter.next();
+        	SingleElementSymbol ses = (SingleElementSymbol) elementIter.next();
+        	if (!(ses instanceof ElementSymbol)) {
+        		continue;
+        	}
+        	ElementSymbol element = (ElementSymbol)ses;
             GroupSymbol group = element.getGroupSymbol();
             List elements = (List) groupMap.get(group);
             if(elements == null) { 

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleChooseDependent.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleChooseDependent.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleChooseDependent.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -39,10 +39,10 @@
 import com.metamatrix.query.optimizer.relational.GenerateCanonical;
 import com.metamatrix.query.optimizer.relational.OptimizerRule;
 import com.metamatrix.query.optimizer.relational.RuleStack;
-import com.metamatrix.query.optimizer.relational.plantree.JoinStrategyType;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants;
 import com.metamatrix.query.optimizer.relational.plantree.NodeEditor;
 import com.metamatrix.query.optimizer.relational.plantree.PlanNode;
+import com.metamatrix.query.processor.relational.JoinNode.JoinStrategyType;
 import com.metamatrix.query.sql.lang.CompareCriteria;
 import com.metamatrix.query.sql.lang.Criteria;
 import com.metamatrix.query.sql.lang.DependentSetCriteria;

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleChooseJoinStrategy.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleChooseJoinStrategy.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleChooseJoinStrategy.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -36,10 +36,10 @@
 import com.metamatrix.query.optimizer.capabilities.CapabilitiesFinder;
 import com.metamatrix.query.optimizer.relational.OptimizerRule;
 import com.metamatrix.query.optimizer.relational.RuleStack;
-import com.metamatrix.query.optimizer.relational.plantree.JoinStrategyType;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants;
 import com.metamatrix.query.optimizer.relational.plantree.NodeEditor;
 import com.metamatrix.query.optimizer.relational.plantree.PlanNode;
+import com.metamatrix.query.processor.relational.JoinNode.JoinStrategyType;
 import com.metamatrix.query.sql.lang.CompareCriteria;
 import com.metamatrix.query.sql.lang.Criteria;
 import com.metamatrix.query.sql.lang.JoinType;

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleImplementJoinStrategy.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleImplementJoinStrategy.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleImplementJoinStrategy.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -37,11 +37,11 @@
 import com.metamatrix.query.optimizer.capabilities.CapabilitiesFinder;
 import com.metamatrix.query.optimizer.relational.OptimizerRule;
 import com.metamatrix.query.optimizer.relational.RuleStack;
-import com.metamatrix.query.optimizer.relational.plantree.JoinStrategyType;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants;
 import com.metamatrix.query.optimizer.relational.plantree.NodeEditor;
 import com.metamatrix.query.optimizer.relational.plantree.NodeFactory;
 import com.metamatrix.query.optimizer.relational.plantree.PlanNode;
+import com.metamatrix.query.processor.relational.JoinNode.JoinStrategyType;
 import com.metamatrix.query.processor.relational.MergeJoinStrategy.SortOption;
 import com.metamatrix.query.sql.lang.JoinType;
 import com.metamatrix.query.sql.lang.OrderBy;
@@ -70,20 +70,31 @@
             if (!JoinStrategyType.MERGE.equals(stype)) {
             	continue;
             } 
-/*            if (joinNode.getProperty(NodeConstants.Info.JOIN_TYPE) == JoinType.JOIN_INNER) {
-            	//there is a possible optimization at runtime here based upon the cardinality
+            
+            /**
+             * Don't push sorts for unbalanced inner joins, we prefer to use partitioning 
+             */
+            boolean pushLeft = true;
+            boolean pushRight = true;
+            if (joinNode.getProperty(NodeConstants.Info.JOIN_TYPE) == JoinType.JOIN_INNER && context != null) {
             	float leftCost = NewCalculateCostUtil.computeCostForTree(joinNode.getFirstChild(), metadata);
             	float rightCost = NewCalculateCostUtil.computeCostForTree(joinNode.getLastChild(), metadata);
-            	if (leftCost != NewCalculateCostUtil.UNKNOWN_VALUE && leftCost < context.getProcessorBatchSize() * context.getProcessorBatchSize()
-            			&& rightCost != NewCalculateCostUtil.UNKNOWN_VALUE && rightCost > context.getProcessorBatchSize()) {
-                    joinNode.setProperty(NodeConstants.Info.SORT_LEFT, SortOption.SORT);
-                    joinNode.setProperty(NodeConstants.Info.SORT_RIGHT, SortOption.SORT);
-            		continue;
+            	boolean leftSmall = leftCost < context.getProcessorBatchSize() / 4;
+            	boolean rightSmall = rightCost < context.getProcessorBatchSize() / 4;
+            	boolean leftLarge = leftCost > context.getProcessorBatchSize();
+            	boolean rightLarge = rightCost > context.getProcessorBatchSize();
+            	if (leftLarge || rightLarge) {
+	                pushLeft = leftCost == NewCalculateCostUtil.UNKNOWN_VALUE || leftSmall || rightLarge;
+	                pushRight = rightCost == NewCalculateCostUtil.UNKNOWN_VALUE || rightSmall || leftLarge || joinNode.getProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE) != null;
             	}
-            }
-*/            
-            insertSort(joinNode.getFirstChild(), (List<SingleElementSymbol>) joinNode.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS), joinNode, metadata, capabilitiesFinder);
-            insertSort(joinNode.getLastChild(), (List<SingleElementSymbol>) joinNode.getProperty(NodeConstants.Info.RIGHT_EXPRESSIONS), joinNode, metadata, capabilitiesFinder);
+            }            
+
+            boolean pushedLeft = insertSort(joinNode.getFirstChild(), (List<SingleElementSymbol>) joinNode.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS), joinNode, metadata, capabilitiesFinder, pushLeft);	
+            insertSort(joinNode.getLastChild(), (List<SingleElementSymbol>) joinNode.getProperty(NodeConstants.Info.RIGHT_EXPRESSIONS), joinNode, metadata, capabilitiesFinder, pushRight);
+        	
+        	if (joinNode.getProperty(NodeConstants.Info.JOIN_TYPE) == JoinType.JOIN_INNER && (!pushRight || !pushedLeft)) {
+        		joinNode.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.PARTITIONED_SORT);
+        	}
         }
         
         return plan;
@@ -98,7 +109,8 @@
      * @throws MetaMatrixComponentException 
      * @throws QueryMetadataException 
      */
-    private static void insertSort(PlanNode childNode, List<SingleElementSymbol> expressions, PlanNode jnode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, MetaMatrixComponentException {
+    private static boolean insertSort(PlanNode childNode, List<SingleElementSymbol> expressions, PlanNode jnode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder,
+    		boolean attemptPush) throws QueryMetadataException, MetaMatrixComponentException {
         Set<SingleElementSymbol> orderSymbols = new LinkedHashSet<SingleElementSymbol>(expressions); 
 
         PlanNode sourceNode = FrameUtil.findJoinSourceNode(childNode);
@@ -116,14 +128,19 @@
         
         PlanNode sortNode = createSortNode(orderSymbols, outputSymbols, directions);
         
-        if (sourceNode.getType() == NodeConstants.Types.ACCESS 
-                        && RuleRaiseAccess.canRaiseOverSort(sourceNode, metadata, capFinder, sortNode)) {
-            sourceNode.getFirstChild().addAsParent(sortNode);
-            
-            if (needsCorrection) {
-                correctOutputElements(joinNode, outputSymbols, sortNode);
-            }
-            return;
+        if (sourceNode.getType() == NodeConstants.Types.ACCESS) {
+        	if (NodeEditor.findAllNodes(sourceNode, NodeConstants.Types.SOURCE).size() == 1 
+        			&& NewCalculateCostUtil.usesKey(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)) {
+	            sourceNode.getFirstChild().addAsParent(sortNode);
+	            
+	            if (needsCorrection) {
+	                correctOutputElements(joinNode, outputSymbols, sortNode);
+	            }
+	            return true;
+	        }
         }
         
         joinNode.setProperty(joinNode.getFirstChild() == childNode ? NodeConstants.Info.SORT_LEFT : NodeConstants.Info.SORT_RIGHT, SortOption.SORT);
@@ -134,6 +151,7 @@
             childNode.addAsParent(projectNode);
             correctOutputElements(joinNode, outputSymbols, projectNode);
         }        
+        return false;
     }
 
     private static PlanNode createSortNode(Collection orderSymbols,

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RulePlanJoins.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RulePlanJoins.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RulePlanJoins.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -44,10 +44,10 @@
 import com.metamatrix.query.optimizer.capabilities.CapabilitiesFinder;
 import com.metamatrix.query.optimizer.relational.OptimizerRule;
 import com.metamatrix.query.optimizer.relational.RuleStack;
-import com.metamatrix.query.optimizer.relational.plantree.JoinStrategyType;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants;
 import com.metamatrix.query.optimizer.relational.plantree.NodeFactory;
 import com.metamatrix.query.optimizer.relational.plantree.PlanNode;
+import com.metamatrix.query.processor.relational.JoinNode.JoinStrategyType;
 import com.metamatrix.query.resolver.util.AccessPattern;
 import com.metamatrix.query.sql.lang.JoinType;
 import com.metamatrix.query.sql.symbol.ElementSymbol;

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RulePlanSorts.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RulePlanSorts.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RulePlanSorts.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -32,13 +32,12 @@
 import com.metamatrix.query.optimizer.capabilities.CapabilitiesFinder;
 import com.metamatrix.query.optimizer.relational.OptimizerRule;
 import com.metamatrix.query.optimizer.relational.RuleStack;
-import com.metamatrix.query.optimizer.relational.plantree.JoinStrategyType;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants;
 import com.metamatrix.query.optimizer.relational.plantree.NodeEditor;
 import com.metamatrix.query.optimizer.relational.plantree.PlanNode;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants.Info;
+import com.metamatrix.query.processor.relational.JoinNode.JoinStrategyType;
 import com.metamatrix.query.processor.relational.MergeJoinStrategy.SortOption;
-import com.metamatrix.query.sql.lang.JoinType;
 import com.metamatrix.query.sql.lang.SetQuery;
 import com.metamatrix.query.util.CommandContext;
 
@@ -76,21 +75,13 @@
 				node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true);
 			}
 			List orderColumns = (List)node.getProperty(NodeConstants.Info.SORT_ORDER);
-			PlanNode possibleSort = NodeEditor.findNodePreOrder(node, NodeConstants.Types.GROUP | NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.ACCESS);
+			PlanNode possibleSort = NodeEditor.findNodePreOrder(node, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE | NodeConstants.Types.ACCESS);
 			if (possibleSort != null) {
-				NodeConstants.Info expr = Info.GROUP_COLS;
-				if (possibleSort.getType() == NodeConstants.Types.JOIN) {
-					if (possibleSort.getProperty(NodeConstants.Info.JOIN_STRATEGY) != JoinStrategyType.MERGE
-						|| possibleSort.getProperty(NodeConstants.Info.JOIN_TYPE) != JoinType.JOIN_INNER) {
-						break;
-					} 
-					expr = Info.LEFT_EXPRESSIONS;
-				}
-				List exprs = (List)possibleSort.getProperty(expr);
+				List exprs = (List)possibleSort.getProperty(Info.GROUP_COLS);
 				if (exprs != null && exprs.containsAll(orderColumns)) {
 					exprs.removeAll(orderColumns);
 					orderColumns.addAll(exprs);
-					possibleSort.setProperty(expr, orderColumns);
+					possibleSort.setProperty(Info.GROUP_COLS, orderColumns);
 					if (node.getParent() == null) {
 						root = node.getFirstChild();
 						root.removeFromParent();
@@ -101,7 +92,56 @@
 						node = nextNode;
 					}
 				}
+				break;
+			} 
+/*			possibleSort = NodeEditor.findNodePreOrder(node, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.ACCESS);
+			if (possibleSort == null) {
+				break;
 			}
+			boolean left = false;
+			if (possibleSort.getType() == NodeConstants.Types.JOIN) {
+				if (possibleSort.getProperty(NodeConstants.Info.JOIN_STRATEGY) != JoinStrategyType.MERGE
+					|| possibleSort.getProperty(NodeConstants.Info.JOIN_TYPE) != JoinType.JOIN_INNER) {
+					break;
+				} 
+				if (FrameUtil.findJoinSourceNode(possibleSort.getFirstChild()).getGroups().containsAll(node.getGroups()) 
+						&& possibleSort.getProperty(NodeConstants.Info.SORT_LEFT) == SortOption.SORT) {
+					left = true;
+				} else if (!FrameUtil.findJoinSourceNode(possibleSort.getLastChild()).getGroups().containsAll(node.getGroups()) 
+						|| possibleSort.getProperty(NodeConstants.Info.SORT_RIGHT) != SortOption.SORT) {
+					break;
+				}
+			}
+			List exprs = (List)possibleSort.getProperty(left?Info.LEFT_EXPRESSIONS:Info.RIGHT_EXPRESSIONS);
+			if (exprs != null && exprs.containsAll(orderColumns)) {
+				List<Integer> indexes = new ArrayList<Integer>(orderColumns.size());
+				for (Expression expr : (List<Expression>)orderColumns) {
+					indexes.add(0, exprs.indexOf(expr));
+				}
+				exprs.removeAll(orderColumns);
+				List newExprs = new ArrayList(orderColumns);
+				newExprs.addAll(exprs);
+				possibleSort.setProperty(left?Info.LEFT_EXPRESSIONS:Info.RIGHT_EXPRESSIONS, newExprs);
+				if (node.getParent() == null) {
+					root = node.getFirstChild();
+					root.removeFromParent();
+					node = root;
+				} else {
+					PlanNode nextNode = node.getFirstChild();
+					NodeEditor.removeChildNode(node.getParent(), node);
+					node = nextNode;
+				}
+				exprs = (List)possibleSort.getProperty(left?Info.RIGHT_EXPRESSIONS:Info.LEFT_EXPRESSIONS);
+				List toRemove = new ArrayList();
+				for (Integer index : indexes) {
+					Object o = exprs.get(index);
+					exprs.add(0, o);
+					toRemove.add(o);
+				}
+				exprs.subList(indexes.size(), exprs.size()).removeAll(toRemove);
+				possibleSort.setProperty(left?NodeConstants.Info.SORT_LEFT:NodeConstants.Info.SORT_RIGHT, SortOption.SORT_REQUIRED);
+			}
+*/
 			break;
 		case NodeConstants.Types.DUP_REMOVE:
 			if (parentBlocking) {
@@ -120,7 +160,7 @@
 			parentBlocking = true;
 			break;
 		case NodeConstants.Types.JOIN:
-			if (node.getProperty(NodeConstants.Info.JOIN_STRATEGY) != JoinStrategyType.MERGE) {
+			if (node.getProperty(NodeConstants.Info.JOIN_STRATEGY) == JoinStrategyType.NESTED_LOOP) {
 				break;
 			}
 			/*
@@ -134,10 +174,16 @@
 			PlanNode toTest = node.getFirstChild();
 			if (mergeSortWithDupRemovalAcrossSource(toTest)) {
 				node.setProperty(NodeConstants.Info.SORT_LEFT, SortOption.SORT_DISTINCT);
+				if (node.getProperty(NodeConstants.Info.SORT_RIGHT) != SortOption.SORT) {
+					node.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE);
+				}
 			}
 			toTest = node.getLastChild();
 			if (mergeSortWithDupRemovalAcrossSource(toTest)) {
 				node.setProperty(NodeConstants.Info.SORT_RIGHT, SortOption.SORT_DISTINCT);
+				if (node.getProperty(NodeConstants.Info.SORT_LEFT) != SortOption.SORT) {
+					node.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE);
+				}
 			}
 			break;
 		case NodeConstants.Types.SET_OP:

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/BatchIterator.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/BatchIterator.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/BatchIterator.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -114,5 +114,10 @@
         	this.currentBatch = null;
         }
     }
+    
+    @Override
+    public TupleBatch getBatch() throws MetaMatrixComponentException {
+		return currentBatch;
+    }
 
 }

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/DependentValueSource.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/DependentValueSource.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/DependentValueSource.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -22,11 +22,17 @@
 
 package com.metamatrix.query.processor.relational;
 
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
 import com.metamatrix.api.exception.MetaMatrixComponentException;
+import com.metamatrix.api.exception.MetaMatrixProcessingException;
 import com.metamatrix.common.buffer.BufferManager;
 import com.metamatrix.common.buffer.IndexedTupleSource;
 import com.metamatrix.common.buffer.TupleSourceID;
 import com.metamatrix.common.buffer.TupleSourceNotFoundException;
+import com.metamatrix.core.util.Assertion;
 import com.metamatrix.query.sql.symbol.Expression;
 import com.metamatrix.query.sql.util.ValueIterator;
 import com.metamatrix.query.sql.util.ValueIteratorSource;
@@ -39,6 +45,7 @@
 
     private TupleSourceID tupleSourceID;
     private BufferManager bm;
+    private Map<Expression, HashSet<Object>> cachedSets;
     
     public DependentValueSource(TupleSourceID tupleSourceID, BufferManager bm) {
         this.tupleSourceID = tupleSourceID;
@@ -64,8 +71,44 @@
     	int index = 0;
     	if (valueExpression != null) {
     		index = its.getSchema().indexOf(valueExpression);
+    		Assertion.assertTrue(index != -1);
     	}
         return new TupleSourceValueIterator(its, index);
     }
+    
+    public HashSet<Object> getCachedSet(Expression valueExpression) throws MetaMatrixComponentException, MetaMatrixProcessingException {
+    	HashSet<Object> result = null;
+    	if (cachedSets != null) {
+    		result = cachedSets.get(valueExpression);
+    	}
+    	if (result == null) {
+    		IndexedTupleSource its;
+    		try {
+    			if (bm.getRowCount(tupleSourceID) > bm.getProcessorBatchSize() / 2) {
+    				return null;
+    			}
+    			its = bm.getTupleSource(tupleSourceID);
+    		} catch (TupleSourceNotFoundException e) {
+    			throw new MetaMatrixComponentException(e);
+    		}
+        	int index = 0;
+        	if (valueExpression != null) {
+        		index = its.getSchema().indexOf(valueExpression);
+        	}
+        	Assertion.assertTrue(index != -1);
+        	result = new HashSet<Object>();
+        	while (its.hasNext()) {
+        		Object value = its.nextTuple().get(index);
+        		if (value != null) {
+        			result.add(value);
+        		}
+        	}
+        	if (cachedSets == null) {
+        		cachedSets = new HashMap<Expression, HashSet<Object>>();
+        	}
+    		cachedSets.put(valueExpression, result);
+    	}
+    	return result;
+    }
            
 }

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/GroupingNode.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/GroupingNode.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/GroupingNode.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -47,6 +47,7 @@
 import com.metamatrix.query.function.aggregate.Min;
 import com.metamatrix.query.function.aggregate.NullFilter;
 import com.metamatrix.query.function.aggregate.Sum;
+import com.metamatrix.query.processor.relational.SortUtility.Mode;
 import com.metamatrix.query.sql.ReservedWords;
 import com.metamatrix.query.sql.lang.OrderBy;
 import com.metamatrix.query.sql.symbol.AggregateSymbol;
@@ -311,8 +312,8 @@
             this.phase = GROUP;
         } else {
             this.sortUtility = new SortUtility(collectionID, sortElements,
-                                                sortTypes, removeDuplicates, getBufferManager(),
-                                                getConnectionID());
+                                                sortTypes, removeDuplicates?Mode.DUP_REMOVE_SORT:Mode.SORT, getBufferManager(),
+                                                getConnectionID(), removeDuplicates);
             this.phase = SORT;
         }
     }

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/JoinNode.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/JoinNode.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/JoinNode.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -47,8 +47,14 @@
  * @since 4.2
  */
 public class JoinNode extends SubqueryAwareRelationalNode {
+	
+	public enum JoinStrategyType {    
+	    MERGE,
+	    PARTITIONED_SORT,
+	    NESTED_LOOP
+	}
         
-    private enum State { LOAD_LEFT, LOAD_RIGHT, EXECUTE }    
+    private enum State { LOAD_LEFT, LOAD_RIGHT, POST_LOAD_LEFT, POST_LOAD_RIGHT, EXECUTE }    
     private State state = State.LOAD_LEFT;
     
     private boolean leftOpened;
@@ -60,6 +66,8 @@
    
     private List leftExpressions;
     private List rightExpressions;
+    private boolean leftDistinct;
+    private boolean rightDistinct;
     private Criteria joinCriteria;
     
     private Map combinedElementMap;
@@ -85,6 +93,22 @@
         this.rightExpressions = rightExpressions;
     }
     
+    public boolean isLeftDistinct() {
+		return leftDistinct;
+	}
+    
+    public void setLeftDistinct(boolean leftDistinct) {
+		this.leftDistinct = leftDistinct;
+	}
+    
+    public boolean isRightDistinct() {
+		return rightDistinct;
+	}
+    
+    public void setRightDistinct(boolean rightDistinct) {
+		this.rightDistinct = rightDistinct;
+	}
+    
     public void setJoinCriteria(Criteria joinCriteria) {
         this.joinCriteria = joinCriteria;
     }
@@ -147,6 +171,8 @@
         
         clonedNode.rightExpressions = rightExpressions;
         clonedNode.dependentValueSource = this.dependentValueSource;
+        clonedNode.rightDistinct = rightDistinct;
+        clonedNode.leftDistinct = leftDistinct;
         
         return clonedNode;
     }
@@ -172,8 +198,17 @@
                 this.rightOpened = true;
             }
             this.joinStrategy.loadRight();
-            state = State.EXECUTE;
+            state = State.POST_LOAD_LEFT;
         }
+        if (state == State.POST_LOAD_LEFT) {
+        	this.joinStrategy.postLoadLeft();
+        	state = State.POST_LOAD_RIGHT;
+        }
+        if (state == State.POST_LOAD_RIGHT) {
+        	this.joinStrategy.postLoadRight();
+        	state = State.EXECUTE;
+        }
+        
         while(true) {
             if(super.isBatchFull()) {
                 return super.pullBatch();
@@ -270,6 +305,9 @@
         } catch (TupleSourceNotFoundException err) {
             //ignore
         }        
+        if (this.isDependent()) {
+        	this.getContext().getVariableContext().setGlobalValue(this.dependentValueSource, null);
+        }
     }
 
     public JoinType getJoinType() {

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/JoinStrategy.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/JoinStrategy.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/JoinStrategy.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -57,16 +57,24 @@
                             throws MetaMatrixComponentException {
         this.joinNode = joinNode;
         this.leftSource = new SourceState(joinNode.getChildren()[0], joinNode.getLeftExpressions());
+        this.leftSource.markDistinct(this.joinNode.isLeftDistinct());
         this.rightSource = new SourceState(joinNode.getChildren()[1], joinNode.getRightExpressions());
+        this.rightSource.markDistinct(this.joinNode.isRightDistinct());
     }
             
     protected void loadLeft() throws MetaMatrixComponentException, MetaMatrixProcessingException {
         this.leftSource.collectTuples();
     }
     
+    protected void postLoadLeft() throws MetaMatrixComponentException, MetaMatrixProcessingException {
+    }
+    
     protected void loadRight() throws MetaMatrixComponentException, MetaMatrixProcessingException {
         this.rightSource.collectTuples();
     }
+    
+    protected void postLoadRight() throws MetaMatrixComponentException, MetaMatrixProcessingException {
+    }
         
     /**
      * Output a combined, projected tuple based on tuple parts from the left and right. 

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/ListNestedSortComparator.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/ListNestedSortComparator.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/ListNestedSortComparator.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -22,7 +22,7 @@
 
 package com.metamatrix.query.processor.relational;
 
-import java.util.*;
+import java.util.List;
 
 import com.metamatrix.core.util.Assertion;
 
@@ -60,18 +60,21 @@
     /**
      * Specifies which fields to sort on.
      */
-    int[] sortParameters;
+    private int[] sortParameters;
 
     /**
      * Indicates whether comparison should be based on ascending or descending
      * order.
      */
-    boolean ascendingOrder = false;
+    private boolean ascendingOrder = false;
 
     /**
      * List of booleans indicating the order in which each column should be sorted
      */
-    List orderTypes = null;
+    private List orderTypes = null;
+    
+    private boolean isDistinct = true;
+    private int distinctIndex;
 
     /**
      * Constructs an instance of this class given the indicies of the parameters
@@ -101,8 +104,15 @@
         this.sortParameters = sortParameters;
         this.orderTypes = orderTypes;
     }
+    
+    public boolean isDistinct() {
+		return isDistinct;
+	}
+    
+    public void setDistinctIndex(int distinctIndex) {
+		this.distinctIndex = distinctIndex;
+	}
 
-
     /**
      * Compares its two arguments for order.  Returns a negative integer,
      * zero, or a positive integer as the first argument is less than,
@@ -119,20 +129,13 @@
      * @param o2 The second object being compared
      */
     public int compare( Object o1, Object o2 ) {
-        // Cast input objects to Lists...
         List list1 = (List)o1;
         List list2 = (List)o2;
 
         int compare = 0;
-        int k = 0;
-        while ( k < sortParameters.length && compare == 0 ) {
+        for (int k = 0; k < sortParameters.length; k++) {
             Object param1 = list1.get(sortParameters[k]);
             Object param2 = list2.get(sortParameters[k]);
-            // if orderTypes is not set
-            if(orderTypes != null) {
-                // getting ordertype for each column
-                ascendingOrder = ((Boolean)orderTypes.get(k)).booleanValue();
-            }
 
             if( param1 == null ) {
 				if(param2 == null ) {
@@ -150,11 +153,15 @@
             } else {
             	Assertion.failed("Expected comparable types"); //$NON-NLS-1$
             }
-            k++;
+            if (compare != 0) {
+            	boolean asc = orderTypes != null?((Boolean)orderTypes.get(k)).booleanValue():this.ascendingOrder;
+                return asc ? compare : -compare;
+            } else if (k == distinctIndex) {
+        		isDistinct = false;
+        	}
         }
-        return ascendingOrder ? compare : -compare;
+    	return 0;
     }
     
 } // END CLASS    
 
-

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/MergeJoinStrategy.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/MergeJoinStrategy.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/MergeJoinStrategy.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -28,6 +28,7 @@
 import com.metamatrix.api.exception.MetaMatrixComponentException;
 import com.metamatrix.api.exception.MetaMatrixProcessingException;
 import com.metamatrix.api.exception.query.CriteriaEvaluationException;
+import com.metamatrix.common.buffer.BlockedOnMemoryException;
 import com.metamatrix.common.buffer.TupleSourceNotFoundException;
 import com.metamatrix.query.processor.relational.SortUtility.Mode;
 import com.metamatrix.query.sql.lang.JoinType;
@@ -46,7 +47,7 @@
  * 
  */
 public class MergeJoinStrategy extends JoinStrategy {
-
+	
     private enum MergeState {
         SCAN, MATCH, DONE
     }
@@ -76,32 +77,33 @@
     
     //planning time information
     public enum SortOption {
-        SKIP_SORT, SORT, SORT_DISTINCT
+        ALREADY_SORTED, SORT, SORT_DISTINCT, PARTITION
     }
     
-    private SortOption sortLeft;
-    private SortOption sortRight;
+    protected SortOption sortLeft;
+    protected SortOption sortRight;
         
     /** false if three-level comparison, true if grouping comparison (null == null) */
     private boolean grouping;
-
+    
     //load time state
     private SortUtility leftSort;
     private SortUtility rightSort;
-    private SortOption processingSortRight;   
+    protected SortOption processingSortLeft;
+    protected SortOption processingSortRight;   
     
     public MergeJoinStrategy(SortOption sortLeft, SortOption sortRight, boolean grouping) {
     	if (sortLeft == null) {
-    		sortLeft = SortOption.SKIP_SORT;
+    		sortLeft = SortOption.ALREADY_SORTED;
     	}
     	if (sortRight == null) {
-    		sortRight = SortOption.SKIP_SORT;
+    		sortRight = SortOption.ALREADY_SORTED;
     	}
         this.sortLeft = sortLeft;
         this.sortRight = sortRight;
         this.grouping = grouping;
     }
-
+    
     /**
      * @see com.metamatrix.query.processor.relational.JoinStrategy#clone()
      */
@@ -125,6 +127,7 @@
         this.rightScanState = ScanState.READ;
         this.outerMatched = false;
         this.processingSortRight = this.sortRight;
+        this.processingSortLeft = this.sortLeft;
     }
 
     /**
@@ -139,10 +142,10 @@
         this.leftSort = null;
         this.rightSort = null;
     }
-
+    
+    @Override
     protected List nextTuple() throws MetaMatrixComponentException,
-                              CriteriaEvaluationException,
-                              MetaMatrixProcessingException {
+    		CriteriaEvaluationException, MetaMatrixProcessingException {
         while (this.mergeState != MergeState.DONE) {
             
             while (this.mergeState == MergeState.SCAN) {
@@ -334,51 +337,68 @@
     @Override
     protected void loadLeft() throws MetaMatrixComponentException,
                              MetaMatrixProcessingException {
-        if (sortLeft != SortOption.SKIP_SORT) { 
+    	if (sortLeft == SortOption.ALREADY_SORTED && !this.joinNode.isDependent() && !JoinType.JOIN_FULL_OUTER.equals(joinNode.getJoinType())) {
+    		return; // don't buffer
+    	}
+        super.loadLeft(); 
+    }
+    
+    @Override
+    protected void postLoadLeft() throws MetaMatrixComponentException,
+    		MetaMatrixProcessingException {
+        if (this.processingSortLeft == SortOption.SORT || this.processingSortLeft == SortOption.SORT_DISTINCT) {
             if (this.leftSort == null) {
-                List expressions = this.joinNode.getLeftExpressions();
-                this.leftSort = new SortUtility(this.leftSource.collectTuples(),
-                                                    expressions, Collections.nCopies(expressions.size(), OrderBy.ASC), sortLeft == SortOption.SORT_DISTINCT?Mode.DUP_REMOVE_SORT:Mode.SORT,
+            	List expressions = this.joinNode.getLeftExpressions();
+                this.leftSort = new SortUtility(this.leftSource.getTupleSourceID(),
+                                                    expressions, Collections.nCopies(expressions.size(), OrderBy.ASC), processingSortLeft == SortOption.SORT_DISTINCT?Mode.DUP_REMOVE_SORT:Mode.SORT,
                                                     this.joinNode.getBufferManager(), this.joinNode.getConnectionID(), true);         
-                this.leftSource.setDistinct(sortLeft == SortOption.SORT_DISTINCT && expressions.size() == this.leftSource.getOuterVals().size());
+                this.leftSource.markDistinct(processingSortLeft == SortOption.SORT_DISTINCT && expressions.size() == this.leftSource.getOuterVals().size());
             }
             this.leftSource.setTupleSource(leftSort.sort());
-        } else if (this.joinNode.isDependent() || JoinType.JOIN_FULL_OUTER.equals(joinNode.getJoinType())) {
-            super.loadLeft(); //buffer only for dependent and full outer joins
-        }
+            this.leftSource.markDistinct(leftSort.isDistinct());
+        }        
     }
-    
-    /** 
-     * @see com.metamatrix.query.processor.relational.JoinStrategy#loadRight()
-     */
+        
     @Override
-    protected void loadRight() throws MetaMatrixComponentException,
-                              MetaMatrixProcessingException {
-        super.loadRight();
-        if (processingSortRight != SortOption.SKIP_SORT) { 
-            if (this.rightSort == null) {
-                List expressions = this.joinNode.getRightExpressions();
-                this.rightSort = new SortUtility(this.rightSource.getTupleSourceID(), 
-                                                    expressions, Collections.nCopies(expressions.size(), OrderBy.ASC), processingSortRight == SortOption.SORT_DISTINCT?Mode.DUP_REMOVE_SORT:Mode.SORT,
-                                                    this.joinNode.getBufferManager(), this.joinNode.getConnectionID(), true);
-                this.rightSource.setDistinct(processingSortRight == SortOption.SORT_DISTINCT && expressions.size() == this.rightSource.getOuterVals().size());
-            }
-            this.rightSource.setTupleSource(rightSort.sort());
-        } 
+    protected void postLoadRight() throws MetaMatrixComponentException,
+    		MetaMatrixProcessingException {
+    	sortRight();
     }
-    
+
+	protected void sortRight() throws MetaMatrixComponentException,
+			TupleSourceNotFoundException, BlockedOnMemoryException {
+		if (this.processingSortRight == SortOption.SORT || this.processingSortRight == SortOption.SORT_DISTINCT) {
+    		if (this.rightSort == null) {
+    		    List expressions = this.joinNode.getRightExpressions();
+    		    this.rightSort = new SortUtility(this.rightSource.getTupleSourceID(), 
+    		                                        expressions, Collections.nCopies(expressions.size(), OrderBy.ASC), processingSortRight == SortOption.SORT_DISTINCT?Mode.DUP_REMOVE_SORT:Mode.SORT,
+    		                                        this.joinNode.getBufferManager(), this.joinNode.getConnectionID(), true);
+    		    this.rightSource.markDistinct(processingSortRight == SortOption.SORT_DISTINCT && expressions.size() == this.rightSource.getOuterVals().size());
+    		}
+    		this.rightSource.setTupleSource(rightSort.sort());
+            this.rightSource.markDistinct(rightSort.isDistinct());
+        }
+	}
+        
     public void setProcessingSortRight(boolean processingSortRight) {
-    	if (processingSortRight && this.processingSortRight == SortOption.SKIP_SORT) {
+    	if (processingSortRight && this.processingSortRight == SortOption.ALREADY_SORTED) {
     		this.processingSortRight = SortOption.SORT;
     	}
     }
+    
+    public String getName() {
+    	return "MERGE JOIN"; //$NON-NLS-1$
+    }
 
     /**
      * @see java.lang.Object#toString()
      */
     @Override
     public String toString() {
-        return "MERGE JOIN"; //$NON-NLS-1$
-    }
+		StringBuffer sb = new StringBuffer();
+		return sb
+				.append(getName())
+				.append(" (").append(sortLeft).append("/").append(sortRight).append(")").toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+	}
 
 }
\ No newline at end of file

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/NestedLoopJoinStrategy.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/NestedLoopJoinStrategy.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/NestedLoopJoinStrategy.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -33,7 +33,7 @@
 public class NestedLoopJoinStrategy extends MergeJoinStrategy {
 
     public NestedLoopJoinStrategy() {
-        super(SortOption.SKIP_SORT, SortOption.SKIP_SORT, false);
+        super(SortOption.ALREADY_SORTED, SortOption.ALREADY_SORTED, false);
     }
     
     /** 

Added: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/PartitionedSortJoin.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/PartitionedSortJoin.java	                        (rev 0)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/PartitionedSortJoin.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -0,0 +1,336 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package com.metamatrix.query.processor.relational;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import com.metamatrix.api.exception.MetaMatrixComponentException;
+import com.metamatrix.api.exception.MetaMatrixProcessingException;
+import com.metamatrix.api.exception.query.CriteriaEvaluationException;
+import com.metamatrix.common.buffer.BlockedOnMemoryException;
+import com.metamatrix.common.buffer.IndexedTupleSource;
+import com.metamatrix.common.buffer.MemoryNotAvailableException;
+import com.metamatrix.common.buffer.TupleBatch;
+import com.metamatrix.common.buffer.TupleSourceID;
+import com.metamatrix.common.buffer.TupleSourceNotFoundException;
+
+/**
+ * Extends the basic fully sorted merge join to check for conditions necessary 
+ * to not fully sort one of the sides
+ * 
+ * Will be used for inner joins and only if both sorts are not required.
+ * Degrades to a normal merge join if the tuples are balanced. 
+ */
+public class PartitionedSortJoin extends MergeJoinStrategy {
+	
+	/**
+	 * This is a compromise between the max size of the smaller side
+	 * and effective partitioning assuming that we only want to hold
+	 * two batches in memory during partitioning.
+	 * 
+	 * TODO: apply partitioning recursively and/or have a better mechanism
+	 * for buffermanager reserve/release of memory 
+	 * (would also help the sort utility)
+	 */
+	public static final int MAX_PARTITIONS = 8; 
+	
+	private List[] endTuples;
+	private List<Boolean> overlap = new ArrayList<Boolean>();
+	private List<Integer> endRows = new ArrayList<Integer>();
+	private List<TupleSourceID> partitionIds = new ArrayList<TupleSourceID>();
+	private List<TupleCollector> tupleCollectors = new ArrayList<TupleCollector>();
+	private int currentPartition;
+	private IndexedTupleSource currentSource;
+	private SourceState sortedSource;
+	private SourceState partitionedSource;
+	private boolean partitioned;
+	private List<?> partitionedTuple;
+	private int matchBegin = -1;
+	private int matchEnd = -1;
+
+	public PartitionedSortJoin(SortOption sortLeft, SortOption sortRight) {
+		super(sortLeft, sortRight, false);
+	}
+	
+    @Override
+    public void close() throws TupleSourceNotFoundException,
+    		MetaMatrixComponentException {
+    	super.close();
+    	for (TupleSourceID tupleSourceID : this.partitionIds) {
+    		try {
+    			this.joinNode.getBufferManager().removeTupleSource(tupleSourceID);
+    		} catch (TupleSourceNotFoundException e) {
+    			
+    		}
+		}
+    	this.endTuples = null;
+    	this.overlap.clear();
+    	this.endRows.clear();
+    	this.partitionIds.clear();
+    	this.tupleCollectors.clear();
+    	this.currentSource = null;
+    	this.sortedSource = null;
+    	this.partitionedSource = null;
+    	this.partitionedTuple = null;
+    }
+    
+    @Override
+    public void initialize(JoinNode joinNode)
+    		throws MetaMatrixComponentException {
+    	super.initialize(joinNode);
+    	this.currentPartition = 0;
+    	this.partitioned = false;
+    	this.matchBegin = -1;
+    	this.matchEnd = -1;
+    }
+	
+    //TODO: save partial work
+    public void computeBatchBounds(SourceState state) throws TupleSourceNotFoundException, MetaMatrixComponentException {
+    	if (endTuples != null) {
+    		return;
+    	}
+    	Comparator comp = new ListNestedSortComparator(state.getExpressionIndexes(), true);
+    	ArrayList<List<?>> bounds = new ArrayList<List<?>>();
+        int beginRow = 1;
+        while (beginRow <= state.getRowCount()) {
+        	TupleBatch batch = null;
+        	try {
+        		batch = this.joinNode.getBufferManager().pinTupleBatch(state.getTupleSourceID(), beginRow, beginRow + this.joinNode.getBatchSize() - 1);
+        		if (batch.getRowCount() == 0) {
+        			break;
+        		}
+        		beginRow = batch.getEndRow() + 1; 
+        		this.joinNode.getBufferManager().unpinTupleBatch(state.getTupleSourceID(), batch.getBeginRow(), batch.getEndRow());
+        		if (!bounds.isEmpty()) {
+        			overlap.add(comp.compare(bounds.get(bounds.size() - 1), batch.getTuple(batch.getBeginRow())) == 0);
+        		}
+        		bounds.add(batch.getTuple(batch.getEndRow()));
+        		endRows.add(batch.getEndRow());
+        	} catch (MemoryNotAvailableException e) {
+        		throw BlockedOnMemoryException.INSTANCE;
+        	} 
+        }
+        this.endTuples = bounds.toArray(new List[bounds.size()]);
+    }
+    
+    @Override
+    protected void loadLeft() throws MetaMatrixComponentException,
+    		MetaMatrixProcessingException {
+    	//always buffer to determine row counts
+    	this.leftSource.collectTuples();
+    }
+    
+    @Override
+    protected void loadRight() throws MetaMatrixComponentException,
+    		MetaMatrixProcessingException {
+    	super.loadRight();
+    	int maxRows = this.joinNode.getBatchSize() * MAX_PARTITIONS;
+    	if (processingSortRight == SortOption.SORT
+    			&& this.leftSource.getRowCount() < maxRows
+    			&& this.leftSource.getRowCount() * 4 < this.rightSource.getRowCount()) {
+    		this.processingSortRight = SortOption.PARTITION;
+    	} else if (processingSortLeft == SortOption.SORT
+    			&& this.rightSource.getRowCount() < maxRows 
+    			&& this.rightSource.getRowCount() * 4 < this.leftSource.getRowCount()) {
+    		this.processingSortLeft = SortOption.PARTITION;
+    	} 
+        sortRight();
+        if (this.processingSortLeft == SortOption.PARTITION) {
+        	computeBatchBounds(this.rightSource);
+        	this.sortedSource = this.rightSource;
+        	this.partitionedSource = this.leftSource;
+        }
+    }
+    
+    @Override
+    protected void postLoadLeft() throws MetaMatrixComponentException,
+    		MetaMatrixProcessingException {
+        super.postLoadLeft();
+
+        if (this.processingSortRight == SortOption.PARTITION) {
+        	computeBatchBounds(this.leftSource);
+        	this.sortedSource = this.leftSource;
+        	this.partitionedSource = this.rightSource;
+        }
+        
+        if (this.processingSortLeft == SortOption.PARTITION) {
+        	partitionSource(true);
+        }        
+    }
+    
+    @Override
+    protected void postLoadRight() throws MetaMatrixComponentException,
+    		MetaMatrixProcessingException {
+    	if (this.processingSortRight == SortOption.PARTITION) {
+    		partitionSource(false);
+        	if (this.processingSortRight == SortOption.SORT) {
+        		//degrade to a merge join
+        		sortRight(); 
+        	}
+    	} 
+    }
+
+	private void partitionSource(boolean left) throws MetaMatrixComponentException,
+			MetaMatrixProcessingException {
+		if (partitioned) {
+			return;
+		}
+		if (endTuples.length > MAX_PARTITIONS + 1) {
+			if (left) {
+				this.processingSortLeft = SortOption.SORT;
+			} else {
+				this.processingSortRight = SortOption.SORT;
+			}
+			return;
+		}
+		if (endTuples.length < 2) {
+			partitionIds.add(this.partitionedSource.getTupleSourceID());
+		} else {
+			if (partitionIds.isEmpty()) {
+				for (int i = 0; i < endTuples.length; i++) {
+					TupleCollector tc = new TupleCollector(this.partitionedSource.createSourceTupleSource(), this.joinNode.getBufferManager());
+					tc.setBatchSize(Math.max(1, this.joinNode.getBatchSize()/4));
+					this.tupleCollectors.add(tc);
+					this.partitionIds.add(tc.getTupleSourceID());
+				}
+			}
+			while (this.partitionedSource.getIterator().hasNext()) {
+				List<?> tuple = this.partitionedSource.getIterator().nextTuple();
+				int index = binarySearch(tuple, this.endTuples, this.partitionedSource.getExpressionIndexes(), this.sortedSource.getExpressionIndexes());
+				if (index < 0) {
+					index = -index - 1;
+				}
+				if (index > this.tupleCollectors.size() -1) {
+					continue;
+				}
+				while (index > 0 && this.overlap.get(index - 1) 
+						&& compare(tuple, this.endTuples[index - 1], this.partitionedSource.getExpressionIndexes(), this.sortedSource.getExpressionIndexes()) == 0) {
+					index--;
+				}
+				this.tupleCollectors.get(index).addTuple(tuple);
+			}
+			this.partitionedSource.getIterator().setPosition(1);
+		}
+		partitioned = true;
+	}
+        
+    @Override
+    protected List nextTuple() throws MetaMatrixComponentException,
+    		CriteriaEvaluationException, MetaMatrixProcessingException {
+    	if (this.processingSortLeft != SortOption.PARTITION && this.processingSortRight != SortOption.PARTITION) {
+    		return super.nextTuple();
+    	}
+    	if (endRows.isEmpty()) {
+    		return null; //no rows on the sorted side
+    	}
+    	while (currentPartition < partitionIds.size()) {
+    		if (currentSource == null) {
+    			if (!this.tupleCollectors.isEmpty()) {
+    				this.tupleCollectors.get(currentPartition).close();
+    			}
+    			currentSource = this.joinNode.getBufferManager().getTupleSource(partitionIds.get(currentPartition));
+    		}
+    		
+    		int beginIndex = currentPartition>0?endRows.get(currentPartition - 1)+1:1;
+    		
+    		this.sortedSource.getIterator().setPosition(beginIndex);
+			List[] batch = this.sortedSource.getIterator().getBatch().getAllTuples();
+						
+    		while (partitionedTuple != null || currentSource.hasNext()) {
+    			if (partitionedTuple == null) {
+    				partitionedTuple = currentSource.nextTuple();
+	    			int index = binarySearch(partitionedTuple, batch, this.partitionedSource.getExpressionIndexes(), this.sortedSource.getExpressionIndexes());
+	    			if (index < 0) {
+	            		partitionedTuple = null;
+	    				continue;
+	    			}
+	    			matchBegin = index;
+	    			matchEnd = index;
+	    			if (!this.sortedSource.isDistinct()) {
+		    			while (matchBegin > 0) {
+		    				if (compare(partitionedTuple, batch[matchBegin - 1], this.partitionedSource.getExpressionIndexes(), this.sortedSource.getExpressionIndexes()) != 0) {
+		    					break;
+		    				}
+		    				matchBegin--;
+		    			}
+		    			while (matchEnd < batch.length - 1) {
+		    				if (compare(partitionedTuple, batch[matchEnd + 1], this.partitionedSource.getExpressionIndexes(), this.sortedSource.getExpressionIndexes()) != 0) {
+		    					break;
+		    				}
+		    				matchEnd++;
+		    			}
+	    			}
+	    			if (matchEnd == batch.length - 1 && currentPartition < overlap.size() && overlap.get(currentPartition)) {
+	    				this.tupleCollectors.get(currentPartition + 1).addTuple(partitionedTuple);
+	    			}
+    			}
+    			while (matchBegin <= matchEnd) {
+    				List outputTuple = outputTuple(this.processingSortLeft==SortOption.PARTITION?partitionedTuple:batch[matchBegin], 
+    						this.processingSortLeft==SortOption.PARTITION?batch[matchBegin]:partitionedTuple);
+    				boolean matches = this.joinNode.matchesCriteria(outputTuple);
+    				matchBegin++;
+                    if (matches) {
+                    	return outputTuple;
+                    }
+    			}
+    			matchBegin = -1;
+    			matchEnd = -1;
+        		partitionedTuple = null;
+    		}
+    		currentSource = null;
+    		currentPartition++;
+    	}
+    	return null;
+    }
+    
+    public int binarySearch(List<?> tuple, List[] tuples, int[] leftIndexes, int[] rightIndexes) {
+    	int begin = 0;
+    	int end = tuples.length - 1;
+    	while (begin <= end) {
+	    	int mid = (begin + end)/2;
+	    	int compare = compare(tuples[mid], tuple, rightIndexes, leftIndexes);
+	    	if (compare == 0) {
+	    		return mid;
+	    	}
+	    	if (compare < 0) {
+	    		end = mid - 1;
+	    	} else {
+	    		begin = mid + 1;
+	    	}
+    	}
+    	return -begin -1;
+    }
+    
+    @Override
+    public Object clone() {
+    	return new PartitionedSortJoin(this.sortLeft, this.sortRight);
+    }
+    
+    @Override
+    public String getName() {
+    	return "PARTITIONED SORT JOIN"; //$NON-NLS-1$
+    }
+       	
+}


Property changes on: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/PartitionedSortJoin.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/SortUtility.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/SortUtility.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/SortUtility.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -25,7 +25,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 
@@ -69,7 +68,7 @@
     protected List schema;
     private String[] schemaTypes;
     protected int[] sortCols;
-	private Comparator comparator;
+	private ListNestedSortComparator comparator;
 
     private TupleSourceID outputID;
 	private IndexedTupleSource outTs;
@@ -78,7 +77,6 @@
     private int phase = INITIAL_SORT;
     protected List<TupleSourceID> activeTupleIDs = new ArrayList<TupleSourceID>();
     private List<TupleBatch> workingBatches;
-    private int[] workingPointers;
     private int masterSortIndex;
 	private TupleSourceID mergedID;
 	private TupleSourceID tempOutId;
@@ -260,8 +258,8 @@
             }
             
             // Initialize pointers into working batches
-            this.workingPointers = new int[workingBatches.size()];
-            Arrays.fill(this.workingPointers, 1);
+            int[] workingPointers = new int[workingBatches.size()];
+            Arrays.fill(workingPointers, 1);
 
             mergedID = createTupleSource();
 
@@ -288,7 +286,7 @@
                         chosenBatchIndex = i;
                         chosenBatch = batch;
                     } else if (compare == 0 && this.mode != Mode.SORT) {
-                    	incrementWorkingBatch(i, batch);
+                    	incrementWorkingBatch(i, workingPointers, batch);
                     }
                 }
 
@@ -305,11 +303,11 @@
                 	}
                     tempCollector.addTuple(currentRow);
                 }
-                incrementWorkingBatch(chosenBatchIndex, chosenBatch);
+                incrementWorkingBatch(chosenBatchIndex, workingPointers, chosenBatch);
             }
 
             // Save without closing
-            collector.saveBatch(false);
+            collector.saveBatch();
             
             // Remove merged sublists
             for(int i=0; i<sortedIndex; i++) {
@@ -363,7 +361,7 @@
 	        		throw new MetaMatrixComponentException(e);
 	        	}
 			} catch (BlockedOnMemoryException e) {
-				tc.saveBatch(false);
+				tc.saveBatch();
 				throw e;
 			}
         	outTs = null;
@@ -375,7 +373,7 @@
      * for that batchIndex, which we already happen to have.  Return whether the batch
      * was changed or not.  True = changed.
      */
-    private void incrementWorkingBatch(int batchIndex, TupleBatch currentBatch) throws BlockedOnMemoryException, TupleSourceNotFoundException, MetaMatrixComponentException {
+    private void incrementWorkingBatch(int batchIndex, int[] workingPointers, TupleBatch currentBatch) throws BlockedOnMemoryException, TupleSourceNotFoundException, MetaMatrixComponentException {
         workingPointers[batchIndex] += 1;
         if(workingPointers[batchIndex] > currentBatch.getEndRow()) {
             TupleSourceID tsID = unpinWorkingBatch(batchIndex, currentBatch);
@@ -411,7 +409,7 @@
         this.schema = this.bufferManager.getTupleSchema(this.sourceID);
         this.schemaTypes = TypeRetrievalUtil.getTypeNames(schema);
         this.batchSize = bufferManager.getProcessorBatchSize();
-        
+        int distinctIndex = sortElements != null? sortElements.size() - 1:0;
         if (useAllColumns && mode != Mode.SORT) {
 	        if (this.sortElements != null) {
 	        	this.sortElements = new ArrayList(this.sortElements);
@@ -438,6 +436,11 @@
         }
         this.sortCols = cols;
         this.comparator = new ListNestedSortComparator(sortCols, sortTypes);
+        this.comparator.setDistinctIndex(distinctIndex);
     }
     
+    public boolean isDistinct() {
+    	return this.comparator.isDistinct();
+    }
+    
 }

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/SourceState.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/SourceState.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/SourceState.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -30,6 +30,8 @@
 import com.metamatrix.common.buffer.IndexedTupleSource;
 import com.metamatrix.common.buffer.TupleSourceID;
 import com.metamatrix.common.buffer.TupleSourceNotFoundException;
+import com.metamatrix.common.buffer.BufferManager.TupleSourceType;
+import com.metamatrix.query.util.TypeRetrievalUtil;
 
 class SourceState {
 
@@ -63,6 +65,10 @@
         return indecies;
     }
     
+    TupleSourceID createSourceTupleSource() throws MetaMatrixComponentException {
+    	return this.source.getBufferManager().createTupleSource(source.getElements(), TypeRetrievalUtil.getTypeNames(source.getElements()), source.getConnectionID(), TupleSourceType.PROCESSOR);
+    }
+    
     public List saveNext() throws MetaMatrixComponentException, MetaMatrixProcessingException {
         this.currentTuple = this.getIterator().nextTuple();
         return currentTuple;
@@ -85,6 +91,10 @@
             this.tsID = null;
         }
     }
+    
+    public int getRowCount() {
+    	return this.collector.getRowCount();
+    }
 
     /**
      * Collect the underlying batches into a tuple source.  Subsequent calls will return that tuple source
@@ -151,8 +161,8 @@
         return this.distinct;
     }
 
-    public void setDistinct(boolean distinct) {
-        this.distinct = distinct;
+    public void markDistinct(boolean distinct) {
+        this.distinct |= distinct;
     }
 
 }

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/TupleCollector.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/TupleCollector.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/TupleCollector.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -36,12 +36,10 @@
 	
 	private TupleSourceID tsid;
 	private BufferManager bm;
-	private boolean captureBounds;
 	
 	private int batchSize;
 	private ArrayList<List<?>> batch;
 	private int index;
-	private ArrayList<List<?>> bounds;
 
 	public TupleCollector(TupleSourceID tsid, BufferManager bm) throws TupleSourceNotFoundException, MetaMatrixComponentException {
 		this.tsid = tsid;
@@ -50,48 +48,64 @@
 		this.index = bm.getRowCount(tsid) + 1;
 	}
 	
-	public void setCaptureBounds(boolean captureBounds) {
-		this.captureBounds = captureBounds;
+	public TupleCollector(BufferManager bm) {
+		this.batchSize = bm.getProcessorBatchSize();
+		this.bm = bm;
+		this.index = 1;
 	}
 	
+	public void setBatchSize(int batchSize) {
+		this.batchSize = batchSize;
+	}
+	
+	public void setTupleSourceID(TupleSourceID tsid) {
+		this.tsid = tsid;
+	}
+	
+	public boolean isEmpty() {
+		return this.batch == null || this.batch.isEmpty();
+	}
+	
 	public TupleSourceID getTupleSourceID() {
 		return tsid;
 	}
 	
+	public ArrayList<List<?>> getBatch() {
+		if (batch == null) {
+			batch = new ArrayList<List<?>>(batchSize/4);
+		}
+		return batch;
+	}
+	
 	public void addTuple(List<?> tuple) throws TupleSourceNotFoundException, MetaMatrixComponentException {
 		if (batch == null) {
 			batch = new ArrayList<List<?>>(batchSize/4);
 		}
 		batch.add(tuple);
 		if (batch.size() == batchSize) {
-			saveBatch(false);
+			saveBatch();
 		}
 	}
 
-	public void saveBatch(boolean isLast) throws TupleSourceNotFoundException,
+	public void saveBatch() throws TupleSourceNotFoundException,
 			MetaMatrixComponentException {
-		ArrayList<List<?>> toSave = batch;
-		if (toSave == null || toSave.isEmpty()) {
-			if (!isLast) {
-				return;
-			}
-			toSave = new ArrayList<List<?>>(0);
-		} /*else if (captureBounds) {
-			if (bounds.isEmpty()) {
-				bounds.add(toSave.get(0));
-			}
-			if (bounds )
-			bounds.add(toSave.get(toSave.size() -1));
-		}*/
-		TupleBatch tb = new TupleBatch(index, toSave);
-		tb.setTerminationFlag(isLast);
-		this.bm.addTupleBatch(tsid, tb);
-		this.index += toSave.size();
-		batch = null;
+		if (batch == null || batch.isEmpty()) {
+			return;
+		}
+		int batchIndex = 0;
+		while(batchIndex < batch.size()) {
+            int writeEnd = Math.min(batch.size(), batchIndex + batchSize);
+
+            TupleBatch writeBatch = new TupleBatch(index, batch.subList(batchIndex, writeEnd));
+            bm.addTupleBatch(tsid, writeBatch);
+            index += writeBatch.getRowCount();
+            batchIndex += writeBatch.getRowCount();
+        }
+        batch = null;
 	}
 	
 	public void close() throws TupleSourceNotFoundException, MetaMatrixComponentException {
-		saveBatch(true);
+		saveBatch();
 		this.bm.setStatus(this.tsid, TupleSourceStatus.FULL);
 	}
 	

Modified: trunk/engine/src/main/java/com/metamatrix/query/sql/util/ValueIteratorSource.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/sql/util/ValueIteratorSource.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/sql/util/ValueIteratorSource.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -22,7 +22,10 @@
 
 package com.metamatrix.query.sql.util;
 
+import java.util.HashSet;
+
 import com.metamatrix.api.exception.MetaMatrixComponentException;
+import com.metamatrix.api.exception.MetaMatrixProcessingException;
 import com.metamatrix.common.buffer.TupleSourceNotFoundException;
 import com.metamatrix.query.sql.symbol.Expression;
 
@@ -47,4 +50,6 @@
      */
     ValueIterator getValueIterator(Expression valueExpression) throws MetaMatrixComponentException;
     
+    HashSet<Object> getCachedSet(Expression valueExpression) throws MetaMatrixComponentException, MetaMatrixProcessingException;
+    
 }

Deleted: trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/DependentSetCriteriaCollectorVisitor.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/DependentSetCriteriaCollectorVisitor.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/DependentSetCriteriaCollectorVisitor.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -1,84 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-package com.metamatrix.query.sql.visitor;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import com.metamatrix.query.sql.LanguageObject;
-import com.metamatrix.query.sql.LanguageVisitor;
-import com.metamatrix.query.sql.lang.DependentSetCriteria;
-import com.metamatrix.query.sql.navigator.DeepPreOrderNavigator;
-
-
-/** 
- * Visitor to collect DependentSetCriteria.  
- */
-public class DependentSetCriteriaCollectorVisitor extends LanguageVisitor {
-
-    // List<DependentSetCriteria>
-    private List crits = new ArrayList();
-    
-    /** 
-     * 
-     */
-    public DependentSetCriteriaCollectorVisitor() {
-        super();
-    }
-
-    /**
-     * Get the criteria collected by the visitor.  This should be called
-     * after the visitor has been run on the language object tree.
-     * @return List of {@link com.metamatrix.query.sql.lang.DependentSetCriteria}
-     */
-    public List getCriteria() {
-        return this.crits;
-    }
-
-    /**
-     * Visit a language object and collect symbols.  This method should <b>NOT</b> be
-     * called directly.
-     * @param obj Language object
-     */
-    public void visit(DependentSetCriteria obj) {
-        this.crits.add(obj);
-    }
-    
-    /**
-     * Get all DependentSetCriteria found in a deep search from the input LanguageObject. 
-     * @param obj Starting language object (criteria, command, etc)
-     * @return List of DependentSetCriteria
-     */
-    public static List getDependentSetCriteria(LanguageObject obj) {
-        if(obj == null) {
-            return Collections.EMPTY_LIST;
-        }
-        
-        DependentSetCriteriaCollectorVisitor visitor = new DependentSetCriteriaCollectorVisitor();
-        DeepPreOrderNavigator.doVisit(obj, visitor);        
-        return visitor.getCriteria();
-        
-    }
-
-}

Modified: trunk/engine/src/main/java/com/metamatrix/query/util/CommandContext.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/util/CommandContext.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/main/java/com/metamatrix/query/util/CommandContext.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -448,13 +448,4 @@
 		return value;
 	}
 	
-	public ValueIterator getValueIterator(ContextReference ref)
-			throws MetaMatrixComponentException {
-		if (variableContext == null) {
-			throw new MetaMatrixComponentException(ErrorMessageKeys.PROCESSOR_0033, QueryPlugin.Util.getString(ErrorMessageKeys.PROCESSOR_0033, ref.getContextSymbol(), "No value was available")); //$NON-NLS-1$
-		}
-		ValueIteratorSource dvs = (ValueIteratorSource) this.variableContext.getGlobalValue(ref.getContextSymbol());
-		return dvs.getValueIterator(ref.getValueExpression());
-	}
-
 }

Modified: trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestLimit.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestLimit.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestLimit.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -742,7 +742,7 @@
                                         0,      // PlanExecution
                                         1,      // Project
                                         0,      // Select
-                                        0,      // Sort
+                                        1,      // Sort
                                         0       // UnionAll
         }, NODE_TYPES);
         

Modified: trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestOptimizer.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestOptimizer.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestOptimizer.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -60,9 +60,11 @@
 import com.metamatrix.query.processor.relational.DependentAccessNode;
 import com.metamatrix.query.processor.relational.GroupingNode;
 import com.metamatrix.query.processor.relational.JoinNode;
+import com.metamatrix.query.processor.relational.JoinStrategy;
 import com.metamatrix.query.processor.relational.MergeJoinStrategy;
 import com.metamatrix.query.processor.relational.NestedLoopJoinStrategy;
 import com.metamatrix.query.processor.relational.NullNode;
+import com.metamatrix.query.processor.relational.PartitionedSortJoin;
 import com.metamatrix.query.processor.relational.PlanExecutionNode;
 import com.metamatrix.query.processor.relational.ProjectIntoNode;
 import com.metamatrix.query.processor.relational.ProjectNode;
@@ -423,11 +425,15 @@
     public static void collectCounts(RelationalNode relationalNode, int[] counts, Class<?>[] types) {
         Class<?> nodeType = relationalNode.getClass();
         if(nodeType.equals(JoinNode.class)) {
-            if (((JoinNode)relationalNode).getJoinStrategy() instanceof NestedLoopJoinStrategy) {
+        	JoinStrategy strategy = ((JoinNode)relationalNode).getJoinStrategy();
+            if (strategy instanceof NestedLoopJoinStrategy) {
                 updateCounts(NestedLoopJoinStrategy.class, counts, types);
-            }else {
+            } else if (strategy instanceof MergeJoinStrategy) {
                 updateCounts(MergeJoinStrategy.class, counts, types);
-            }
+                if (strategy instanceof PartitionedSortJoin) {
+                    updateCounts(PartitionedSortJoin.class, counts, types);
+                } 
+            } 
             if (((JoinNode)relationalNode).isDependent()) {
                 updateCounts(DependentJoin.class, counts, types);
             }

Added: trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestPartitionedJoinPlanning.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestPartitionedJoinPlanning.java	                        (rev 0)
+++ trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestPartitionedJoinPlanning.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -0,0 +1,84 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Licensed to Red Hat, Inc. under one or more contributor 
+ * license agreements.  See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package com.metamatrix.query.optimizer;
+
+import static com.metamatrix.query.optimizer.TestOptimizer.*;
+
+import org.junit.Test;
+
+import com.metamatrix.query.optimizer.capabilities.BasicSourceCapabilities;
+import com.metamatrix.query.optimizer.capabilities.FakeCapabilitiesFinder;
+import com.metamatrix.query.optimizer.capabilities.SourceCapabilities.Capability;
+import com.metamatrix.query.processor.ProcessorPlan;
+import com.metamatrix.query.processor.relational.PartitionedSortJoin;
+import com.metamatrix.query.unittest.FakeMetadataFacade;
+import com.metamatrix.query.unittest.FakeMetadataFactory;
+import com.metamatrix.query.unittest.FakeMetadataObject;
+
+public class TestPartitionedJoinPlanning {
+	
+    @Test public void testUsePartitionedMergeJoin(){
+        // Create query
+        String sql = "SELECT pm1.g1.e1 FROM pm1.g1, pm1.g2 WHERE pm1.g1.e1 = pm1.g2.e1";//$NON-NLS-1$
+
+        FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+        BasicSourceCapabilities caps = new BasicSourceCapabilities();
+        caps.setCapabilitySupport(Capability.QUERY_WHERE, true);
+        caps.setCapabilitySupport(Capability.QUERY_WHERE_COMPARE, true);
+        caps.setCapabilitySupport(Capability.QUERY_WHERE_COMPARE_EQ, true);
+        caps.setCapabilitySupport(Capability.QUERY_WHERE_AND, true);
+        caps.setCapabilitySupport(Capability.QUERY_FROM_GROUP_ALIAS, true);
+        caps.setCapabilitySupport(Capability.QUERY_ORDERBY, true);
+        capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+
+        FakeMetadataFacade metadata = FakeMetadataFactory.example1();
+        FakeMetadataObject g1 = metadata.getStore().findObject("pm1.g1", FakeMetadataObject.GROUP); //$NON-NLS-1$
+        g1.putProperty(FakeMetadataObject.Props.CARDINALITY, 600);
+        FakeMetadataObject g2 = metadata.getStore().findObject("pm1.g2", FakeMetadataObject.GROUP); //$NON-NLS-1$
+        g2.putProperty(FakeMetadataObject.Props.CARDINALITY, 3000);
+    
+        ProcessorPlan plan = helpPlan(sql, metadata,  
+            null, capFinder,
+            new String[] { "SELECT pm1.g1.e1 FROM pm1.g1 ORDER BY pm1.g1.e1", "SELECT pm1.g2.e1 FROM pm1.g2" }, SHOULD_SUCCEED); //$NON-NLS-1$ //$NON-NLS-2$
+        checkNodeTypes(plan, new int[] {
+            2,      // Access
+            0,      // DependentAccess
+            0,      // DependentSelect
+            0,      // DependentProject
+            0,      // DupRemove
+            0,      // Grouping
+            0,      // NestedLoopJoinStrategy
+            1,      // MergeJoinStrategy
+            0,      // Null
+            0,      // PlanExecution
+            1,      // Project
+            0,      // Select
+            0,      // Sort
+            0       // UnionAll
+        });  
+        checkNodeTypes(plan, new int[] {1}, new Class[] {PartitionedSortJoin.class});
+    }    
+
+
+}


Property changes on: trunk/engine/src/test/java/com/metamatrix/query/optimizer/TestPartitionedJoinPlanning.java
___________________________________________________________________
Name: svn:mergeinfo
   + 

Modified: trunk/engine/src/test/java/com/metamatrix/query/optimizer/relational/rules/TestRuleChooseDependent.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/optimizer/relational/rules/TestRuleChooseDependent.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/test/java/com/metamatrix/query/optimizer/relational/rules/TestRuleChooseDependent.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -38,10 +38,10 @@
 import com.metamatrix.query.optimizer.TestOptimizer;
 import com.metamatrix.query.optimizer.capabilities.FakeCapabilitiesFinder;
 import com.metamatrix.query.optimizer.relational.RuleStack;
-import com.metamatrix.query.optimizer.relational.plantree.JoinStrategyType;
 import com.metamatrix.query.optimizer.relational.plantree.NodeConstants;
 import com.metamatrix.query.optimizer.relational.plantree.NodeFactory;
 import com.metamatrix.query.optimizer.relational.plantree.PlanNode;
+import com.metamatrix.query.processor.relational.JoinNode.JoinStrategyType;
 import com.metamatrix.query.rewriter.QueryRewriter;
 import com.metamatrix.query.sql.lang.CompareCriteria;
 import com.metamatrix.query.sql.lang.CompoundCriteria;

Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/TestProcessor.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/TestProcessor.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/TestProcessor.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -95,10 +95,6 @@
 
 public class TestProcessor extends TestCase {
 
-    private TimestampUtil tsUtil = new TimestampUtil();
-	
-	// ################################## FRAMEWORK ################################
-	
 	public TestProcessor(String name) { 
 		super(name);
 	}	
@@ -4615,7 +4611,7 @@
         
        // Create expected results
        List[] expected = new List[] { 
-           Arrays.asList(new Object[] { new Integer(1), Boolean.TRUE, new Double(2.0), tsUtil.createDate(103, 10, 4)  })
+           Arrays.asList(new Object[] { new Integer(1), Boolean.TRUE, new Double(2.0), TimestampUtil.createDate(103, 10, 4)  })
        };    
     
        // Construct data manager with data

Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNode.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNode.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNode.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -22,13 +22,16 @@
 
 package com.metamatrix.query.processor.relational;
 
+import static org.junit.Assert.*;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
 
 import com.metamatrix.api.exception.MetaMatrixComponentException;
 import com.metamatrix.api.exception.MetaMatrixProcessingException;
@@ -39,6 +42,7 @@
 import com.metamatrix.query.function.FunctionDescriptor;
 import com.metamatrix.query.function.FunctionLibraryManager;
 import com.metamatrix.query.processor.FakeDataManager;
+import com.metamatrix.query.processor.relational.MergeJoinStrategy.SortOption;
 import com.metamatrix.query.sql.lang.CompareCriteria;
 import com.metamatrix.query.sql.lang.JoinType;
 import com.metamatrix.query.sql.symbol.Constant;
@@ -47,39 +51,33 @@
 import com.metamatrix.query.sql.symbol.Function;
 import com.metamatrix.query.util.CommandContext;
 
-public class TestJoinNode extends TestCase {
+public class TestJoinNode {
     private static final int NO_CRITERIA = 0;
     private static final int EQUAL_CRITERIA = 1;
     private static final int FUNCTION_CRITERIA = 2;
     
     private int criteriaType = EQUAL_CRITERIA;
     
-    private JoinType joinType;
+    protected JoinType joinType;
     
-    private List[] leftTuples = createTuples1();
-    private List[] rightTuples = createTuples2();
+    protected List[] leftTuples;
+    protected List[] rightTuples;
     
-    private List[] expected;
+    protected List[] expected;
     private List[] expectedReversed;
     
-    private boolean expectSwap = false;
-    private boolean expectSwapReversed = false;
-    
-    private JoinNode join;
-    private JoinStrategy joinStrategy;
+    protected JoinNode join;
+    protected JoinStrategy joinStrategy;
     private RelationalNode leftNode;
     private RelationalNode rightNode;
-
+    
     private FakeDataManager dataMgr;
 
-    public TestJoinNode(String testName) {
-        super(testName);
+    @Before public void setup() {
+    	leftTuples = createTuples1();
+    	rightTuples = createTuples2();
     }
-    
-    protected int getProcessorBatchSize() {
-        return 100;
-    }
-    
+
     protected List[] createTuples1() {
         return new List[] { 
             Arrays.asList(new Object[] { new Integer(5) }),    
@@ -166,7 +164,7 @@
         return createTuples(startingValue, count, true);
     }
     
-    private void helpCreateJoin() {
+    protected void helpCreateJoin() {
         ElementSymbol es1 = new ElementSymbol("e1"); //$NON-NLS-1$
         es1.setType(DataTypeManager.DefaultDataClasses.INTEGER);
         
@@ -189,7 +187,7 @@
         
         join = new JoinNode(3);
         joinStrategy = new NestedLoopJoinStrategy();
-        join.setJoinStrategy(joinStrategy);
+    	join.setJoinStrategy(joinStrategy);
         join.setElements(joinElements);
         join.setJoinType(joinType);
         
@@ -198,7 +196,9 @@
                 break;
 
             case EQUAL_CRITERIA :
-                join.setJoinCriteria(new CompareCriteria(es1, CompareCriteria.EQ, es2));
+                join.setJoinExpressions(Arrays.asList(es1), Arrays.asList(es2));
+                joinStrategy = new MergeJoinStrategy(SortOption.SORT, SortOption.SORT, false);
+                join.setJoinStrategy(joinStrategy);
                 break;
 
             case FUNCTION_CRITERIA :
@@ -213,20 +213,22 @@
     }
         
     public void helpTestJoin() throws MetaMatrixComponentException, MetaMatrixProcessingException {
-        helpTestJoinDirect(expected, expectSwap);
-        helpTestJoinReversed();
+    	for (int batchSize : new int[] {1, 10, leftTuples.length, 100}) {
+	        helpCreateJoin();                
+	        helpTestJoinDirect(expected, batchSize);
+	        List[] temp = leftTuples;
+	        leftTuples = rightTuples;
+	        rightTuples = temp;
+	        helpCreateJoin();                
+	        helpTestJoinDirect(expectedReversed, batchSize);
+	        temp = leftTuples;
+	        leftTuples = rightTuples;
+	        rightTuples = temp;
+    	}
     }
-
-    private void helpTestJoinReversed() throws MetaMatrixComponentException, MetaMatrixProcessingException {
-        List[] temp = leftTuples;
-        leftTuples = rightTuples;
-        rightTuples = temp;
-        helpTestJoinDirect(expectedReversed, expectSwapReversed);        
-    }
     
-    public void helpTestJoinDirect(List[] expectedResults, boolean swapExpected) throws MetaMatrixComponentException, MetaMatrixProcessingException {
-        helpCreateJoin();                
-        BufferManager mgr = NodeTestUtil.getTestBufferManager(1, getProcessorBatchSize());
+    public void helpTestJoinDirect(List[] expectedResults, int batchSize) throws MetaMatrixComponentException, MetaMatrixProcessingException {
+        BufferManager mgr = NodeTestUtil.getTestBufferManager(1, batchSize);
         CommandContext context = new CommandContext("pid", "test", null, null, null);               //$NON-NLS-1$ //$NON-NLS-2$
         
         join.addChild(leftNode);
@@ -244,23 +246,21 @@
                 TupleBatch batch = join.nextBatch();
                 for(int row = currentRow; row <= batch.getEndRow(); row++) {
                     List tuple = batch.getTuple(row);
-                    //System.out.println(tuple);
                     assertEquals("Rows don't match at " + row, expectedResults[row-1], tuple); //$NON-NLS-1$
                 }
-                
+                currentRow += batch.getRowCount();    
                 if(batch.getTerminationFlag()) {
                     break;
                 }
-                currentRow += batch.getRowCount();    
             } catch(BlockedException e) {
                 // ignore and retry
             }
         }
-        
+        assertEquals(expectedResults.length, currentRow - 1);
         join.close(); 
     }
     
-    public void testNoRows() throws Exception {
+    @Test public void testNoRows() throws Exception {
         leftTuples = new List[0];
         rightTuples = new List[0];
         joinType = JoinType.JOIN_INNER;
@@ -269,105 +269,64 @@
         helpTestJoin();        
     }
 
-    public void testInnerJoin() throws Exception {
+    @Test public void testInnerJoin() throws Exception {
         joinType = JoinType.JOIN_INNER;
         expected = new List[] {
+        	Arrays.asList(new Object[] { new Integer(1), new Integer(1) }),    
             Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
             Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-            Arrays.asList(new Object[] { new Integer(1), new Integer(1) }),    
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) })            
         };
-        expectedReversed = new List[] {
-            Arrays.asList(new Object[] { new Integer(1), new Integer(1) }),    
-            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),            
-            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
-            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
-            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-            Arrays.asList(new Object[] { new Integer(4), new Integer(4) })    
-        };
+        expectedReversed = expected;
         helpTestJoin();        
     }
 
-//    public void testRightOuterJoin() {
-//        joinType = JoinType.JOIN_RIGHT_OUTER;
-//        expected = new List[] {
-//            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
-//            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
-//            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-//            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-//            Arrays.asList(new Object[] { new Integer(1), new Integer(1) }),    
-//            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-//            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),            
-//            Arrays.asList(new Object[] { null, null }),    
-//            Arrays.asList(new Object[] { null, new Integer(7) }),    
-//            Arrays.asList(new Object[] { null, new Integer(7) }),    
-//            Arrays.asList(new Object[] { null, new Integer(6) })            
-//        };
-//        expectedReversed = new List[] {
-//            Arrays.asList(new Object[] { new Integer(1), new Integer(1) }),    
-//            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-//            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),            
-//            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
-//            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
-//            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-//            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),   
-//            Arrays.asList(new Object[] { null, new Integer(5) }),    
-//            Arrays.asList(new Object[] { null, new Integer(3) }),
-//            Arrays.asList(new Object[] { null, new Integer(10) }),            
-//            Arrays.asList(new Object[] { null, new Integer(11) }),    
-//            Arrays.asList(new Object[] { null, new Integer(11) })           
-//        };
-//        helpTestJoin();        
-//    }
-
-    public void testLeftOuterJoin() throws Exception {
+    @Test public void testLeftOuterJoin() throws Exception {
         joinType = JoinType.JOIN_LEFT_OUTER;
         expected = new List[] {
-            Arrays.asList(new Object[] { new Integer(5), null }),    
-            Arrays.asList(new Object[] { new Integer(3), null }),    
+            Arrays.asList(new Object[] { new Integer(1), new Integer(1) }),    
             Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
             Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
+            Arrays.asList(new Object[] { new Integer(3), null }),    
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-            Arrays.asList(new Object[] { new Integer(1), new Integer(1) }),    
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),            
+            Arrays.asList(new Object[] { new Integer(5), null }),    
             Arrays.asList(new Object[] { new Integer(10), null }),            
             Arrays.asList(new Object[] { new Integer(11), null }),    
             Arrays.asList(new Object[] { new Integer(11), null })            
         };
         expectedReversed = new List[] {
+        	Arrays.asList(new Object[] { null, null }),    
             Arrays.asList(new Object[] { new Integer(1), new Integer(1) }),    
-            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),            
             Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
             Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),    
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
+            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),            
             Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
-            Arrays.asList(new Object[] { null, null }),    
+            Arrays.asList(new Object[] { new Integer(4), new Integer(4) }),    
+            Arrays.asList(new Object[] { new Integer(6), null }),
             Arrays.asList(new Object[] { new Integer(7), null }),    
-            Arrays.asList(new Object[] { new Integer(7), null }),    
-            Arrays.asList(new Object[] { new Integer(6), null })            
+            Arrays.asList(new Object[] { new Integer(7), null })    
         };
         helpTestJoin();        
     }    
 
-    public void testLeftOuterJoinWithSwap() throws Exception {
-        int outerSize = getProcessorBatchSize() + 1;
+    @Test public void testLeftOuterJoinWithSwap() throws Exception {
+        int outerSize = 11;
         leftTuples = createTuples(1,outerSize);
         rightTuples = createTuples(201,outerSize+1);
         joinType = JoinType.JOIN_LEFT_OUTER;
-        expectSwap = true;
         expected = createResults(1, outerSize);
         expectedReversed = createResults(201, outerSize+1);
         helpTestJoin(); 
     }    
 
-    public void testCrossJoin() throws Exception {
+    @Test public void testCrossJoin() throws Exception {
         joinType = JoinType.JOIN_CROSS;
         criteriaType = NO_CRITERIA;
         expected = new List[] {
@@ -548,7 +507,7 @@
         helpTestJoin();
     }
     
-    public void testInnerJoinWithLookupFunction() throws Exception {
+    @Test public void testInnerJoinWithLookupFunction() throws Exception {
         criteriaType = FUNCTION_CRITERIA;
         joinType = JoinType.JOIN_INNER;
         expected = new List[] {
@@ -565,9 +524,7 @@
             Arrays.asList(new Object[] { new Integer(4), new Integer(5) }),    
             Arrays.asList(new Object[] { new Integer(2), new Integer(3) }),    
             Arrays.asList(new Object[] { new Integer(2), new Integer(3) }),    
-            Arrays.asList(new Object[] { new Integer(4), new Integer(5) }),    
-            Arrays.asList(new Object[] { new Integer(10), new Integer(7) }),    
-            Arrays.asList(new Object[] { new Integer(10), new Integer(7) })            
+            Arrays.asList(new Object[] { new Integer(4), new Integer(5) })    
                 };
 
         dataMgr = new FakeDataManager();
@@ -585,34 +542,179 @@
         helpTestJoin();        
     }    
     
-    public void testFullOuterJoin() throws Exception {
+    @Test public void testFullOuterJoin() throws Exception {
         this.joinType = JoinType.JOIN_FULL_OUTER;
         this.leftTuples = createTuples3();
         this.rightTuples = createTuples4();
         expected = new List[] {
            Arrays.asList(new Object[] { null, null }),  
            Arrays.asList(new Object[] { null, null }),  
-           Arrays.asList(new Object[] { new Integer(10), new Integer(10) }),    
-           Arrays.asList(new Object[] { new Integer(10), new Integer(10) }),    
-           Arrays.asList(new Object[] { new Integer(9), new Integer(9) }),
-           Arrays.asList(new Object[] { new Integer(9), new Integer(9) }),
-           Arrays.asList(new Object[] { new Integer(9), new Integer(9) }),
            Arrays.asList(new Object[] { null, null }), 
+           Arrays.asList(new Object[] { null, null }),
+           Arrays.asList(new Object[] { null, null }),
+           Arrays.asList(new Object[] { null, null }),
            Arrays.asList(new Object[] { new Integer(1), new Integer(1) }), 
            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),
            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),
            Arrays.asList(new Object[] { new Integer(3), null }),
-           Arrays.asList(new Object[] { new Integer(5), new Integer(5) }),
-           Arrays.asList(new Object[] { new Integer(15), null }),
            Arrays.asList(new Object[] { null, new Integer(4) }),
            Arrays.asList(new Object[] { null, new Integer(4) }),
-           Arrays.asList(new Object[] { null, null }),
+           Arrays.asList(new Object[] { new Integer(5), new Integer(5) }),
+           Arrays.asList(new Object[] { null, new Integer(6) }),
            Arrays.asList(new Object[] { null, new Integer(7) }),
-           Arrays.asList(new Object[] { null, new Integer(6) }),
-           Arrays.asList(new Object[] { null, null }),
-           Arrays.asList(new Object[] { null, null })
+           Arrays.asList(new Object[] { new Integer(9), new Integer(9) }),
+           Arrays.asList(new Object[] { new Integer(9), new Integer(9) }),
+           Arrays.asList(new Object[] { new Integer(9), new Integer(9) }),
+           Arrays.asList(new Object[] { new Integer(10), new Integer(10) }),    
+           Arrays.asList(new Object[] { new Integer(10), new Integer(10) }),    
+           Arrays.asList(new Object[] { new Integer(15), null })
         };
-        
-        helpTestJoinDirect(expected, false);
+        expectedReversed = new List[] {
+            Arrays.asList(new Object[] { null, null }),  
+            Arrays.asList(new Object[] { null, null }),  
+            Arrays.asList(new Object[] { null, null }), 
+            Arrays.asList(new Object[] { null, null }),
+            Arrays.asList(new Object[] { null, null }),
+            Arrays.asList(new Object[] { null, null }),
+            Arrays.asList(new Object[] { new Integer(1), new Integer(1) }), 
+            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),
+            Arrays.asList(new Object[] { new Integer(2), new Integer(2) }),
+            Arrays.asList(new Object[] { null, 3 }),
+            Arrays.asList(new Object[] { 4, null }),
+            Arrays.asList(new Object[] { 4, null }),
+            Arrays.asList(new Object[] { new Integer(5), new Integer(5) }),
+            Arrays.asList(new Object[] { 6, null }),
+            Arrays.asList(new Object[] { 7, null }),
+            Arrays.asList(new Object[] { new Integer(9), new Integer(9) }),
+            Arrays.asList(new Object[] { new Integer(9), new Integer(9) }),
+            Arrays.asList(new Object[] { new Integer(9), new Integer(9) }),
+            Arrays.asList(new Object[] { new Integer(10), new Integer(10) }),    
+            Arrays.asList(new Object[] { new Integer(10), new Integer(10) }),    
+            Arrays.asList(new Object[] { null, 15 })
+        };
+        helpTestJoin();
     }
+    
+    @Test public void testMergeJoinOptimization() throws Exception {
+        this.joinType = JoinType.JOIN_INNER;
+        int rows = 100;
+        List[] data = new List[rows];
+        for(int i=0; i<rows; i++) { 
+            data[i] = new ArrayList();
+            Integer value = new Integer((i*17) % 47);
+            data[i].add(value);
+        }
+        this.leftTuples = data;
+        this.rightTuples = createTuples2();
+        expected = new List[] {
+           Arrays.asList(new Object[] { 4, 4 }),
+           Arrays.asList(new Object[] { 4, 4 }),
+           Arrays.asList(new Object[] { 7, 7 }),
+           Arrays.asList(new Object[] { 7, 7 }),
+           Arrays.asList(new Object[] { 2, 2 }),
+           Arrays.asList(new Object[] { 2, 2 }),
+           Arrays.asList(new Object[] { 6, 6 }),
+           Arrays.asList(new Object[] { 1, 1 }),  
+           Arrays.asList(new Object[] { 4, 4 }),
+           Arrays.asList(new Object[] { 4, 4 }),
+           Arrays.asList(new Object[] { 7, 7 }),
+           Arrays.asList(new Object[] { 7, 7 }),
+           Arrays.asList(new Object[] { 2, 2 }),
+           Arrays.asList(new Object[] { 2, 2 }),
+           Arrays.asList(new Object[] { 6, 6 }),
+           Arrays.asList(new Object[] { 1, 1 }),
+           Arrays.asList(new Object[] { 4, 4 }),
+           Arrays.asList(new Object[] { 4, 4 }),
+        };
+        helpCreateJoin();               
+        this.joinStrategy = new PartitionedSortJoin(SortOption.SORT, SortOption.SORT);
+        this.join.setJoinStrategy(joinStrategy);
+        helpTestJoinDirect(expected, 100);
+    }
+    
+    @Test public void testMergeJoinOptimizationNoRows() throws Exception {
+        this.joinType = JoinType.JOIN_INNER;
+        this.leftTuples = createTuples1();
+        this.rightTuples = new List[] {};
+        expected = new List[] {};
+        helpCreateJoin();               
+        this.joinStrategy = new PartitionedSortJoin(SortOption.SORT, SortOption.SORT);
+        this.join.setJoinStrategy(joinStrategy);
+        helpTestJoinDirect(expected, 100);
+    }
+    
+    @Test public void testMergeJoinOptimizationWithDistinct() throws Exception {
+        this.joinType = JoinType.JOIN_INNER;
+        int rows = 50;
+        List[] data = new List[rows];
+        for(int i=0; i<rows; i++) { 
+            data[i] = new ArrayList();
+            Integer value = new Integer((i*17) % 47);
+            data[i].add(value);
+        }
+        this.leftTuples = data;
+        this.rightTuples = new List[] {
+            Arrays.asList(4),
+            Arrays.asList(7),
+            Arrays.asList(2),
+            Arrays.asList(6),
+            Arrays.asList(1),  
+            Arrays.asList(8),
+        };
+        expected = new List[] {
+           Arrays.asList(new Object[] { 4, 4 }),
+           Arrays.asList(new Object[] { 8, 8 }),
+           Arrays.asList(new Object[] { 7, 7 }),
+           Arrays.asList(new Object[] { 2, 2 }),
+           Arrays.asList(new Object[] { 6, 6 }),
+           Arrays.asList(new Object[] { 1, 1 })
+        };
+        helpCreateJoin();               
+        this.joinStrategy = new PartitionedSortJoin(SortOption.SORT, SortOption.SORT);
+        this.join.setJoinStrategy(joinStrategy);
+        this.join.setRightDistinct(true);
+        helpTestJoinDirect(expected, 100);
+    }
+    
+    @Test public void testMergeJoinOptimizationWithMultiplePartitions() throws Exception {
+        this.joinType = JoinType.JOIN_INNER;
+        int rows = 30;
+        List[] data = new List[rows];
+        for(int i=0; i<rows; i++) { 
+            data[i] = new ArrayList();
+            Integer value = new Integer(i % 17);
+            data[i].add(value);
+        }
+        this.rightTuples = data;
+        this.leftTuples = new List[] {
+            Arrays.asList(4),
+            Arrays.asList(7),
+            Arrays.asList(2),
+            Arrays.asList(6),
+            Arrays.asList(6),
+            Arrays.asList(1),  
+            Arrays.asList(8),
+        };
+        expected = new List[] {
+           Arrays.asList(new Object[] { 1, 1 }),
+           Arrays.asList(new Object[] { 2, 2 }),
+           Arrays.asList(new Object[] { 4, 4 }),
+           Arrays.asList(new Object[] { 6, 6 }),
+           Arrays.asList(new Object[] { 1, 1 }),
+           Arrays.asList(new Object[] { 2, 2 }),
+           Arrays.asList(new Object[] { 4, 4 }),
+           Arrays.asList(new Object[] { 6, 6 }),
+           Arrays.asList(new Object[] { 7, 7 }),
+           Arrays.asList(new Object[] { 8, 8 }),
+           Arrays.asList(new Object[] { 7, 7 }),
+           Arrays.asList(new Object[] { 8, 8 }),
+           Arrays.asList(new Object[] { 6, 6 }),
+           Arrays.asList(new Object[] { 6, 6 }),           
+        };
+        helpCreateJoin();               
+        this.joinStrategy = new PartitionedSortJoin(SortOption.SORT, SortOption.SORT);
+        this.join.setJoinStrategy(joinStrategy);
+        helpTestJoinDirect(expected, 4);
+    }
+
 }

Deleted: trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSize1.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSize1.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSize1.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -1,34 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-package com.metamatrix.query.processor.relational;
-
-public class TestJoinNodeWithProcessorBatchSize1 extends TestJoinNode {
-
-    public TestJoinNodeWithProcessorBatchSize1(String testName) {
-        super(testName);
-    }
-    
-    protected int getProcessorBatchSize() {
-        return 1;
-    }    
-}

Deleted: trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSize10.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSize10.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSize10.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -1,34 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-package com.metamatrix.query.processor.relational;
-
-public class TestJoinNodeWithProcessorBatchSize10 extends TestJoinNode {
-
-    public TestJoinNodeWithProcessorBatchSize10(String testName) {
-        super(testName);
-    }
-    
-    protected int getProcessorBatchSize() {
-        return 10;
-    }    
-}

Deleted: trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSizeSameAsTupleCount.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSizeSameAsTupleCount.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestJoinNodeWithProcessorBatchSizeSameAsTupleCount.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -1,34 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-package com.metamatrix.query.processor.relational;
-
-public class TestJoinNodeWithProcessorBatchSizeSameAsTupleCount extends TestJoinNode {
-
-    public TestJoinNodeWithProcessorBatchSizeSameAsTupleCount(String testName) {
-        super(testName);
-    }
-    
-    protected int getProcessorBatchSize() {
-        return createTuples1().length;
-    }    
-}

Modified: trunk/test-integration/src/test/java/com/metamatrix/systemmodel/TestSystemVirtualModel.java
===================================================================
--- trunk/test-integration/src/test/java/com/metamatrix/systemmodel/TestSystemVirtualModel.java	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/test-integration/src/test/java/com/metamatrix/systemmodel/TestSystemVirtualModel.java	2009-05-04 13:21:45 UTC (rev 857)
@@ -272,14 +272,14 @@
 				"PartsSupplier	PartsSupplier.PARTSSUPPLIER.STATUS	STATUS_ID	PK_STATUS	Primary	STATUS	STATUS	null	mmuuid:25a8a740-73ff-1edc-a81c-ecf397b10590	1", //$NON-NLS-1$
 				"PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER	SUPPLIER_ID	PK_SUPPLIER	Primary	SUPPLIER	SUPPLIER	null	mmuuid:375c8380-73ff-1edc-a81c-ecf397b10590	1", //$NON-NLS-1$
 				"PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER	SUPPLIER_STATUS	FK_SPLIER_STATS	Foreign	SUPPLIER	SUPPLIER	mmuuid:25a8a740-73ff-1edc-a81c-ecf397b10590	mmuuid:5ac43c00-73ff-1edc-a81c-ecf397b10590	1", //$NON-NLS-1$
+				"PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	PART_ID	FK_SPLIER_PRTS_PRTS	Foreign	SUPPLIER_PARTS	SUPPLIER_PARTS	mmuuid:07db4240-73ff-1edc-a81c-ecf397b10590	mmuuid:66ddc4c0-73ff-1edc-a81c-ecf397b10590	1", //$NON-NLS-1$
 				"PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	PART_ID	PK_SUPPLIER_PARTS	Primary	SUPPLIER_PARTS	SUPPLIER_PARTS	null	mmuuid:455e5440-73ff-1edc-a81c-ecf397b10590	2", //$NON-NLS-1$
-				"PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	PART_ID	FK_SPLIER_PRTS_PRTS	Foreign	SUPPLIER_PARTS	SUPPLIER_PARTS	mmuuid:07db4240-73ff-1edc-a81c-ecf397b10590	mmuuid:66ddc4c0-73ff-1edc-a81c-ecf397b10590	1", //$NON-NLS-1$
+				"PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	SUPPLIER_ID	FK_SPLY_PRTS_SPLY	Foreign	SUPPLIER_PARTS	SUPPLIER_PARTS	mmuuid:375c8380-73ff-1edc-a81c-ecf397b10590	mmuuid:66ddc4c1-73ff-1edc-a81c-ecf397b10590	1", //$NON-NLS-1$
 				"PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	SUPPLIER_ID	PK_SUPPLIER_PARTS	Primary	SUPPLIER_PARTS	SUPPLIER_PARTS	null	mmuuid:455e5440-73ff-1edc-a81c-ecf397b10590	1", //$NON-NLS-1$
-				"PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	SUPPLIER_ID	FK_SPLY_PRTS_SPLY	Foreign	SUPPLIER_PARTS	SUPPLIER_PARTS	mmuuid:375c8380-73ff-1edc-a81c-ecf397b10590	mmuuid:66ddc4c1-73ff-1edc-a81c-ecf397b10590	1", //$NON-NLS-1$
 
 		};
 		executeAndAssertResults(
-				"select* from System.KeyElements order by GroupFullName, Name", //$NON-NLS-1$
+				"select* from System.KeyElements order by GroupFullName, Name, KeyName", //$NON-NLS-1$
 				expected);
 	}
 
@@ -1001,18 +1001,18 @@
 	@Test public void testOASTATISTICS() {
 		String[] expected = {
 				"TABLE_QUALIFIER[string]	TABLE_OWNER[string]	TABLE_NAME[string]	NON_UNIQUE[short]	INDEX_QUALIFIER[string]	INDEX_NAME[string]	OA_TYPE[short]	SEQ_IN_INDEX[short]	COLUMN_NAME[string]	OA_COLLATION[string]	OA_CARDINALITY[string]	OA_PAGES[string]	FILTER_CONDITIONS[string]", //$NON-NLS-1$
+				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	PARTS	0		PK_PARTS	3	1	PART_ID	null	null	null", //$NON-NLS-1$
 				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SHIP_VIA	0		PK_SHIP_VIA	3	1	SHIPPER_ID	null	null	null	", //$NON-NLS-1$
 				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	STATUS	0		PK_STATUS	3	1	STATUS_ID	null	null	null	", //$NON-NLS-1$
+				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SUPPLIER	1		FK_SPLIER_STATS	3	1	SUPPLIER_STATUS	null	null	null	", //$NON-NLS-1$
 				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SUPPLIER	0		PK_SUPPLIER	3	1	SUPPLIER_ID	null	null	null	", //$NON-NLS-1$
-				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SUPPLIER	1		FK_SPLIER_STATS	3	1	SUPPLIER_STATUS	null	null	null	", //$NON-NLS-1$
-				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SUPPLIER_PARTS	0		PK_SUPPLIER_PARTS	3	1	SUPPLIER_ID	null	null	null	", //$NON-NLS-1$
+				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SUPPLIER_PARTS	1		FK_SPLIER_PRTS_PRTS	3	1	PART_ID	null	null	null	", //$NON-NLS-1$
 				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SUPPLIER_PARTS	1		FK_SPLY_PRTS_SPLY	3	1	SUPPLIER_ID	null	null	null	", //$NON-NLS-1$
 				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SUPPLIER_PARTS	0		PK_SUPPLIER_PARTS	3	2	PART_ID	null	null	null	", //$NON-NLS-1$
-				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SUPPLIER_PARTS	1		FK_SPLIER_PRTS_PRTS	3	1	PART_ID	null	null	null	", //$NON-NLS-1$
-				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	PARTS	0		PK_PARTS	3	1	PART_ID	null	null	null", //$NON-NLS-1$
+				"PartsSupplier	PartsSupplier/PARTSSUPPLIER	SUPPLIER_PARTS	0		PK_SUPPLIER_PARTS	3	1	SUPPLIER_ID	null	null	null	", //$NON-NLS-1$
 
 		};
-		executeAndAssertResults("select* FROM System.ODBC.OA_STATISTICS", //$NON-NLS-1$
+		executeAndAssertResults("select* FROM System.ODBC.OA_STATISTICS order by TABLE_NAME, INDEX_NAME, COLUMN_NAME", //$NON-NLS-1$
 				expected);
 
 	}
@@ -1025,16 +1025,16 @@
 				"		SHIP_VIA	SHIPPER_ID			null	null	1	null	null	null	PK_SHIP_VIA", //$NON-NLS-1$
 				"		STATUS	STATUS_ID			SUPPLIER	SUPPLIER_STATUS	1	null	null	FK_SPLIER_STATS	PK_STATUS", //$NON-NLS-1$
 				"		SUPPLIER	SUPPLIER_ID			SUPPLIER_PARTS	SUPPLIER_ID	1	null	null	FK_SPLY_PRTS_SPLY	PK_SUPPLIER", //$NON-NLS-1$
+				"		SUPPLIER	SUPPLIER_STATUS			null	null	1	null	null	null	FK_SPLIER_STATS", //$NON-NLS-1$
+				"		SUPPLIER_PARTS	PART_ID			null	null	2	null	null	null	PK_SUPPLIER_PARTS", //$NON-NLS-1$
 				"		SUPPLIER_PARTS	SUPPLIER_ID			null	null	1	null	null	null	PK_SUPPLIER_PARTS", //$NON-NLS-1$
-				"		SUPPLIER_PARTS	PART_ID			null	null	2	null	null	null	PK_SUPPLIER_PARTS", //$NON-NLS-1$
-				"		SUPPLIER	SUPPLIER_STATUS			null	null	1	null	null	null	FK_SPLIER_STATS", //$NON-NLS-1$
 				"		SUPPLIER_PARTS	PART_ID			null	null	1	null	null	null	FK_SPLIER_PRTS_PRTS", //$NON-NLS-1$
 				"		SUPPLIER_PARTS	SUPPLIER_ID			null	null	1	null	null	null	FK_SPLY_PRTS_SPLY", //$NON-NLS-1$
 
 		};
 
 		executeAndAssertResults(
-				"select '' AS PKTABLE_QUALIFIER, '' AS PKTABLE_OWNER, PK.GroupName AS PKTABLE_NAME, PK.Name AS PKCOLUMN_NAME, '' AS FKTABLE_QUALIFIER, '' AS FKTABLE_OWNER, FK.GroupName AS FKTABLE_NAME, FK.Name AS FKCOLUMN_NAME, convert(PK.Position, short) AS KEY_SEQ, convert(null, short) AS UPDATE_RULE, convert(null, short) AS DELETE_RULE, FK.KeyName AS FK_NAME, PK.KeyName AS PK_NAME FROM System.KeyElements AS PK LEFT OUTER JOIN System.KeyElements AS FK ON FK.RefKeyUID = PK.UID", //$NON-NLS-1$
+				"select '' AS PKTABLE_QUALIFIER, '' AS PKTABLE_OWNER, PK.GroupName AS PKTABLE_NAME, PK.Name AS PKCOLUMN_NAME, '' AS FKTABLE_QUALIFIER, '' AS FKTABLE_OWNER, FK.GroupName AS FKTABLE_NAME, FK.Name AS FKCOLUMN_NAME, convert(PK.Position, short) AS KEY_SEQ, convert(null, short) AS UPDATE_RULE, convert(null, short) AS DELETE_RULE, FK.KeyName AS FK_NAME, PK.KeyName AS PK_NAME FROM System.KeyElements AS PK LEFT OUTER JOIN System.KeyElements AS FK ON FK.RefKeyUID = PK.UID order by PKTABLE_NAME", //$NON-NLS-1$
 				expected);
 	}
 
@@ -1063,11 +1063,12 @@
 	@Test public void testReferenceKeyColumns() {
 		String[] expected = {
 				"PKTABLE_CAT[string]	PKTABLE_SCHEM[string]	PKTABLE_NAME[string]	PKCOLUMN_NAME[string]	FKTABLE_CAT[string]	FKTABLE_SCHEM[string]	FKTABLE_NAME[string]	FKCOLUMN_NAME[string]	KEY_SEQ[short]	UPDATE_RULE[integer]	DELETE_RULE[integer]	FK_NAME[string]	PK_NAME[string]	DEFERRABILITY[integer]", //$NON-NLS-1$
+				"null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.PARTS	PART_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	PART_ID	1	3	3	FK_SPLIER_PRTS_PRTS	PK_PARTS	5",  //$NON-NLS-1$
 				"null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.STATUS	STATUS_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER	SUPPLIER_STATUS	1	3	3	FK_SPLIER_STATS	PK_STATUS	5", //$NON-NLS-1$
-				"null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER	SUPPLIER_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	SUPPLIER_ID	1	3	3	FK_SPLY_PRTS_SPLY	PK_SUPPLIER	5", //$NON-NLS-1$
-				"null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.PARTS	PART_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	PART_ID	1	3	3	FK_SPLIER_PRTS_PRTS	PK_PARTS	5", }; //$NON-NLS-1$
+				"null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER	SUPPLIER_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	SUPPLIER_ID	1	3	3	FK_SPLY_PRTS_SPLY	PK_SUPPLIER	5" //$NON-NLS-1$
+		};
 
-		executeAndAssertResults("select* FROM System.JDBC.ReferenceKeyColumns", //$NON-NLS-1$
+		executeAndAssertResults("select* FROM System.JDBC.ReferenceKeyColumns order by PKTABLE_NAME", //$NON-NLS-1$
 				expected);
 	}
 	

Modified: trunk/test-integration/src/test/resources/partssupplier/expected/CrossReference.txt
===================================================================
--- trunk/test-integration/src/test/resources/partssupplier/expected/CrossReference.txt	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/test-integration/src/test/resources/partssupplier/expected/CrossReference.txt	2009-05-04 13:21:45 UTC (rev 857)
@@ -1,4 +1,4 @@
 PKTABLE_CAT[string]	PKTABLE_SCHEM[string]	PKTABLE_NAME[string]	PKCOLUMN_NAME[string]	FKTABLE_CAT[string]	FKTABLE_SCHEM[string]	FKTABLE_NAME[string]	FKCOLUMN_NAME[string]	KEY_SEQ[short]	UPDATE_RULE[integer]	DELETE_RULE[integer]	FK_NAME[string]	PK_NAME[string]	DEFERRABILITY[integer]	
 null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.STATUS	STATUS_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER	SUPPLIER_STATUS	1	3	3	FK_SPLIER_STATS	PK_STATUS	5
+null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.PARTS	PART_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	PART_ID	1	3	3	FK_SPLIER_PRTS_PRTS	PK_PARTS	5
 null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER	SUPPLIER_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	SUPPLIER_ID	1	3	3	FK_SPLY_PRTS_SPLY	PK_SUPPLIER	5
-null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.PARTS	PART_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	PART_ID	1	3	3	FK_SPLIER_PRTS_PRTS	PK_PARTS	5

Modified: trunk/test-integration/src/test/resources/partssupplier/expected/ExportedKeys.txt
===================================================================
--- trunk/test-integration/src/test/resources/partssupplier/expected/ExportedKeys.txt	2009-05-02 00:13:45 UTC (rev 856)
+++ trunk/test-integration/src/test/resources/partssupplier/expected/ExportedKeys.txt	2009-05-04 13:21:45 UTC (rev 857)
@@ -1,4 +1,4 @@
 PKTABLE_CAT[string]	PKTABLE_SCHEM[string]	PKTABLE_NAME[string]	PKCOLUMN_NAME[string]	FKTABLE_CAT[string]	FKTABLE_SCHEM[string]	FKTABLE_NAME[string]	FKCOLUMN_NAME[string]	KEY_SEQ[short]	UPDATE_RULE[integer]	DELETE_RULE[integer]	FK_NAME[string]	PK_NAME[string]	DEFERRABILITY[integer]	
 null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.STATUS	STATUS_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER	SUPPLIER_STATUS	1	3	3	FK_SPLIER_STATS	PK_STATUS	5
+null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.PARTS	PART_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	PART_ID	1	3	3	FK_SPLIER_PRTS_PRTS	PK_PARTS	5
 null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER	SUPPLIER_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	SUPPLIER_ID	1	3	3	FK_SPLY_PRTS_SPLY	PK_SUPPLIER	5
-null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.PARTS	PART_ID	null	PartsSupplier	PartsSupplier.PARTSSUPPLIER.SUPPLIER_PARTS	PART_ID	1	3	3	FK_SPLIER_PRTS_PRTS	PK_PARTS	5




More information about the teiid-commits mailing list