[teiid-commits] teiid SVN: r3009 - in trunk: common-core/src/test/java/org/teiid/core/util and 7 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Fri Mar 18 21:18:44 EDT 2011


Author: shawkins
Date: 2011-03-18 21:18:44 -0400 (Fri, 18 Mar 2011)
New Revision: 3009

Modified:
   trunk/common-core/src/main/java/org/teiid/core/util/ReflectionHelper.java
   trunk/common-core/src/test/java/org/teiid/core/util/TestReflectionHelper.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
   trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java
   trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/Select.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
Log:
TEIID-1497 expanding the checks performed in the rewriter to allow more conversions to joins

Modified: trunk/common-core/src/main/java/org/teiid/core/util/ReflectionHelper.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/util/ReflectionHelper.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/common-core/src/main/java/org/teiid/core/util/ReflectionHelper.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -40,8 +40,8 @@
 
 public class ReflectionHelper {
 
-    private Class targetClass;
-    private Map methodMap = null;       // used for the brute-force method finder
+    private Class<?> targetClass;
+    private Map<String, LinkedList<Method>> methodMap = null;       // used for the brute-force method finder
 
     /**
      * Construct a ReflectionHelper instance that cache's some information about
@@ -50,7 +50,7 @@
      * @param targetClass the target class
      * @throws IllegalArgumentException if the target class is null
      */
-    public ReflectionHelper( Class targetClass ) {
+    public ReflectionHelper( Class<?> targetClass ) {
         if ( targetClass == null ) {
             throw new IllegalArgumentException(CorePlugin.Util.getString("ReflectionHelper.errorConstructing")); //$NON-NLS-1$
         }
@@ -79,10 +79,10 @@
     		return findBestMethodWithSignature(methodName, Collections.EMPTY_LIST);
     	}
         int size = arguments.length;
-        List argumentClasses = new ArrayList(size);
+        List<Class<?>> argumentClasses = new ArrayList<Class<?>>(size);
         for (int i=0; i!=size; ++i) {
             if ( arguments[i] != null ) {
-                Class clazz = arguments[i].getClass();
+                Class<?> clazz = arguments[i].getClass();
                 argumentClasses.add( clazz );
             } else {
                 argumentClasses.add(null);
@@ -122,7 +122,7 @@
      * @throws NoSuchMethodException if a matching method is not found.
      * @throws SecurityException if access to the information is denied.
      */
-    public Method findBestMethodWithSignature( String methodName, List argumentsClasses ) throws NoSuchMethodException, SecurityException {
+    public Method findBestMethodWithSignature( String methodName, List<Class<?>> argumentsClasses ) throws NoSuchMethodException, SecurityException {
         // Attempt to find the method
         Method result = null;
         Class[] classArgs = new Class[argumentsClasses.size()];
@@ -141,7 +141,7 @@
         // ---------------------------------------------------------------------------------------------
         // Then try to find a method with the argument classes converted to a primitive, if possible ...
         // ---------------------------------------------------------------------------------------------
-        List argumentsClassList = convertArgumentClassesToPrimitives(argumentsClasses);
+        List<Class<?>> argumentsClassList = convertArgumentClassesToPrimitives(argumentsClasses);
         argumentsClassList.toArray(classArgs);
         try {
             result = this.targetClass.getMethod(methodName,classArgs);  // this may throw an exception if not found
@@ -156,20 +156,20 @@
         // the arguments).  There is no canned algorithm in Java to do this, so we have to brute-force it.
         // ---------------------------------------------------------------------------------------------
         if ( this.methodMap == null ) {
-            this.methodMap = new HashMap();
+            this.methodMap = new HashMap<String, LinkedList<Method>>();
             Method[] methods = this.targetClass.getMethods();
             for ( int i=0; i!=methods.length; ++i ) {
                 Method method = methods[i];
-                LinkedList methodsWithSameName = (LinkedList) this.methodMap.get(method.getName());
+                LinkedList<Method> methodsWithSameName = this.methodMap.get(method.getName());
                 if ( methodsWithSameName == null ) {
-                    methodsWithSameName = new LinkedList();
+                    methodsWithSameName = new LinkedList<Method>();
                     this.methodMap.put(method.getName(),methodsWithSameName);
                 }
                 methodsWithSameName.addFirst(method);   // add lower methods first
             }
         }
 
-        LinkedList<Method> methodsWithSameName = (LinkedList) this.methodMap.get(methodName);
+        LinkedList<Method> methodsWithSameName = this.methodMap.get(methodName);
         if ( methodsWithSameName == null ) {
             throw new NoSuchMethodException(methodName);
         }
@@ -180,8 +180,8 @@
             }
             boolean allMatch = true;            // assume all args match
             for ( int i=0; i<args.length && allMatch == true; ++i ) {
-                Class primitiveClazz = (Class) argumentsClassList.get(i);
-                Class objectClazz = (Class) argumentsClasses.get(i);
+                Class<?> primitiveClazz = argumentsClassList.get(i);
+                Class<?> objectClazz = argumentsClasses.get(i);
                 if ( objectClazz != null ) {
                     // Check for possible matches with (converted) primitive types
                     // as well as the original Object type 
@@ -216,11 +216,9 @@
      * @return the list of Class instances in which any classes that could be represented
      * by primitives (e.g., Boolean) were replaced with the primitive classes (e.g., Boolean.TYPE).
      */
-    private static List convertArgumentClassesToPrimitives( List arguments ) {
-        List result = new ArrayList(arguments.size());
-        Iterator iter = arguments.iterator();
-        while ( iter.hasNext() ) {
-            Class clazz = (Class) iter.next();
+    private static List<Class<?>> convertArgumentClassesToPrimitives( List<Class<?>> arguments ) {
+        List<Class<?>> result = new ArrayList<Class<?>>(arguments.size());
+        for (Class<?> clazz : arguments) {
             if      ( clazz == Boolean.class   ) clazz = Boolean.TYPE;
             else if ( clazz == Character.class ) clazz = Character.TYPE;
             else if ( clazz == Byte.class      ) clazz = Byte.TYPE;
@@ -244,8 +242,8 @@
      * @return Class is the instance of the class 
      * @throws ClassNotFoundException 
      */
-    private static final Class loadClass(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
-        Class cls = null;
+    private static final Class<?> loadClass(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
+        Class<?> cls = null;
         if ( classLoader == null ) {
             cls = Class.forName(className.trim());
         } else {
@@ -290,9 +288,9 @@
     public static final Object create(String className, Object[] ctorObjs, Class<?>[] argTypes, 
                 final ClassLoader classLoader) throws TeiidException {
         try {
-            final Class cls = loadClass(className,classLoader);
+            final Class<?> cls = loadClass(className,classLoader);
 
-            Constructor ctor = cls.getDeclaredConstructor(argTypes);
+            Constructor<?> ctor = cls.getDeclaredConstructor(argTypes);
 
             return ctor.newInstance(ctorObjs);
             

Modified: trunk/common-core/src/test/java/org/teiid/core/util/TestReflectionHelper.java
===================================================================
--- trunk/common-core/src/test/java/org/teiid/core/util/TestReflectionHelper.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/common-core/src/test/java/org/teiid/core/util/TestReflectionHelper.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -22,28 +22,21 @@
 
 package org.teiid.core.util;
 
+import static org.junit.Assert.*;
+
 import java.io.Serializable;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.teiid.core.util.ReflectionHelper;
+import org.junit.Test;
 
-import junit.framework.TestCase;
-
 /**
  * TestReflectionHelper
  */
-public class TestReflectionHelper extends TestCase {
+ at SuppressWarnings("unchecked")
+public class TestReflectionHelper {
 
-    /**
-     * Constructor for TestReflectionHelper.
-     * @param name
-     */
-    public TestReflectionHelper(String name) {
-        super(name);
-    }
-
     // =========================================================================
     //                      H E L P E R   M E T H O D S
     // =========================================================================
@@ -68,7 +61,7 @@
     //                         T E S T     C A S E S
     // =========================================================================
 
-    public void testConstructorWithNullTargetClass() {
+    @Test public void testConstructorWithNullTargetClass() {
         try {
             new ReflectionHelper(null);
             fail("Should have caught null target class passed to constructor"); //$NON-NLS-1$
@@ -77,7 +70,7 @@
         }
     }
 
-    public void testConstructorWithValidTargetClass() {
+    @Test public void testConstructorWithValidTargetClass() {
         final ReflectionHelper helper = new ReflectionHelper(String.class);
         assertNotNull(helper);
     }
@@ -85,7 +78,7 @@
     //  ===============================================================================================
     //   Test overloaded methods
     //  ===============================================================================================
-    public void testFindBestMethodWithSignature_String() throws Exception {
+    @Test public void testFindBestMethodWithSignature_String() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {String.class};
         Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -98,7 +91,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_Serializable() throws Exception {
+    @Test public void testFindBestMethodWithSignature_Serializable() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Serializable.class};
         Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -111,7 +104,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_Object() throws Exception {
+    @Test public void testFindBestMethodWithSignature_Object() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {NullPointerException.class};
         try {
@@ -122,7 +115,7 @@
         }
     }
 
-    public void testFindBestMethodWithSignature_StringArray() throws Exception {
+    @Test public void testFindBestMethodWithSignature_StringArray() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {String[].class};
         Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -135,7 +128,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_Integer() throws Exception {
+    @Test public void testFindBestMethodWithSignature_Integer() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Integer.class};
         Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -148,7 +141,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_long() throws Exception {
+    @Test public void testFindBestMethodWithSignature_long() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Long.TYPE};
         Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -161,7 +154,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_2ArgSerializableAndNumber() throws Exception {
+    @Test public void testFindBestMethodWithSignature_2ArgSerializableAndNumber() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Integer.class, Integer.class};
         Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -177,7 +170,7 @@
     //  ===============================================================================================
     //   Test explicit method names
     //  ===============================================================================================
-    public void testFindBestMethodWithSignature_StringAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_StringAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {String.class};
         Method theMethod = helper.findBestMethodWithSignature("methodString", signatureSought ); //$NON-NLS-1$
@@ -190,7 +183,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_ObjectAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_ObjectAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {NullPointerException.class};
         Method theMethod = helper.findBestMethodWithSignature("methodObject", signatureSought ); //$NON-NLS-1$
@@ -203,7 +196,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_SerializableAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_SerializableAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {NullPointerException.class};
         Method theMethod = helper.findBestMethodWithSignature("methodSerializable", signatureSought ); //$NON-NLS-1$
@@ -216,7 +209,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_ObjectSerializableAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_ObjectSerializableAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {NullPointerException.class};
         Method theMethod = helper.findBestMethodWithSignature("methodSerializable", signatureSought ); //$NON-NLS-1$
@@ -229,7 +222,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_IntegerSerializableAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_IntegerSerializableAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Integer.class};
         Method theMethod = helper.findBestMethodWithSignature("methodSerializable", signatureSought ); //$NON-NLS-1$
@@ -242,7 +235,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_StringArrayAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_StringArrayAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {String[].class};
         Method theMethod = helper.findBestMethodWithSignature("methodStringArray", signatureSought ); //$NON-NLS-1$
@@ -255,7 +248,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_ListAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_ListAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {ArrayList.class};
         Method theMethod = helper.findBestMethodWithSignature("methodList", signatureSought ); //$NON-NLS-1$
@@ -268,7 +261,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_IntegerAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_IntegerAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Integer.class};
         Method theMethod = helper.findBestMethodWithSignature("methodInteger", signatureSought ); //$NON-NLS-1$
@@ -281,7 +274,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_IntegerObjectAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_IntegerObjectAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Integer.class};
         Method theMethod = helper.findBestMethodWithSignature("methodObject", signatureSought ); //$NON-NLS-1$
@@ -294,7 +287,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_LongObjectAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_LongObjectAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Long.class};
         Method theMethod = helper.findBestMethodWithSignature("methodObject", signatureSought ); //$NON-NLS-1$
@@ -307,7 +300,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_longAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_longAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Long.TYPE};
         Method theMethod = helper.findBestMethodWithSignature("method_long", signatureSought ); //$NON-NLS-1$
@@ -323,7 +316,7 @@
     //  ===============================================================================================
     //   Test 2-arg methods
     //  ===============================================================================================
-    public void testFindBestMethodWithSignature_2ArgIntegerObjectAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_2ArgIntegerObjectAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Integer.class, Integer.class};
         Method theMethod = helper.findBestMethodWithSignature("twoArgMethod_Object_Object", signatureSought ); //$NON-NLS-1$
@@ -336,7 +329,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_2ArgLongObjectAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_2ArgLongObjectAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Long.class, Long.class};
         Method theMethod = helper.findBestMethodWithSignature("twoArgMethod_Object_Object", signatureSought ); //$NON-NLS-1$
@@ -349,7 +342,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_2ArgSerializableNumberAndMethodName() throws Exception {
+    @Test public void testFindBestMethodWithSignature_2ArgSerializableNumberAndMethodName() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
         Class[] signatureSought = new Class[] {Long.class, Long.class};
         Method theMethod = helper.findBestMethodWithSignature("twoArgMethod_Serializable_Number", signatureSought ); //$NON-NLS-1$
@@ -365,7 +358,7 @@
     //  ===============================================================================================
     //   Test overridden methods
     //  ===============================================================================================
-    public void testFindBestMethodWithSignature_SubInterface_2ArgSerializableAndNumber() throws Exception {
+    @Test public void testFindBestMethodWithSignature_SubInterface_2ArgSerializableAndNumber() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeSubInterface.class);
         Class[] signatureSought = new Class[] {Serializable.class, Number.class};
         Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -378,7 +371,7 @@
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
 
-    public void testFindBestMethodWithSignature_SubInterface_2ArgSerializableAndLong() throws Exception {
+    @Test public void testFindBestMethodWithSignature_SubInterface_2ArgSerializableAndLong() throws Exception {
         ReflectionHelper helper = new ReflectionHelper(FakeSubInterface.class);
         Class[] signatureSought = new Class[] {Serializable.class, Long.class};
         Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -390,12 +383,12 @@
         assertEquals("Wrong class", theMethod.getDeclaringClass().getName(), FakeSubInterface.class.getName()); //$NON-NLS-1$
         helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
     }
-
+    
     /**
      * Test base interface
      */
     public interface FakeInterface {
-
+    	
         void method(String arg);
         void method(Serializable arg);
         void method(Object arg);

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -186,7 +186,7 @@
 		Map<ElementSymbol, List<Set<Constant>>> partitionInfo = (Map<ElementSymbol, List<Set<Constant>>>)child.getProperty(Info.PARTITION_INFO);
 
 		//check to see if any aggregate is dependent upon cardinality
-		boolean cardinalityDependent = RuleRemoveOptionalJoins.areAggregatesCardinalityDependent(aggregates);
+		boolean cardinalityDependent = AggregateSymbol.areAggregatesCardinalityDependent(aggregates);
 
 		LinkedList<PlanNode> unionChildren = new LinkedList<PlanNode>();
 		findUnionChildren(unionChildren, cardinalityDependent, setOp);
@@ -747,7 +747,7 @@
             if (originatingNode.getParent() == groupNode) {
             	//anything logically applied after the join and is
             	//dependent upon the cardinality prevents us from optimizing.
-            	if (aggs && RuleRemoveOptionalJoins.isCardinalityDependent((AggregateSymbol)aggregateSymbol)) {
+            	if (aggs && ((AggregateSymbol)aggregateSymbol).isCardinalityDependent()) {
             		return null;
             	}
                 continue;

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -226,7 +226,7 @@
 				}
 				case NodeConstants.Types.GROUP: {
 					Set<AggregateSymbol> aggs = RulePushAggregates.collectAggregates(parent);
-					return areAggregatesCardinalityDependent(aggs);
+					return AggregateSymbol.areAggregatesCardinalityDependent(aggs);
 				}
 				case NodeConstants.Types.TUPLE_LIMIT: {
 					if (!(parent.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT) instanceof Constant) 
@@ -245,33 +245,7 @@
 		return true;
 	}
 
-	static boolean areAggregatesCardinalityDependent(Set<AggregateSymbol> aggs) {
-		for (AggregateSymbol aggregateSymbol : aggs) {
-			if (isCardinalityDependent(aggregateSymbol)) {
-				return true;
-			}
-		}
-		return false;
-	}
-	
-	static boolean isCardinalityDependent(AggregateSymbol aggregateSymbol) {
-		if (aggregateSymbol.isDistinct()) {
-			return false;
-		}
-		switch (aggregateSymbol.getAggregateFunction()) {
-		case COUNT:
-		case AVG:
-		case STDDEV_POP:
-		case STDDEV_SAMP:
-		case VAR_POP:
-		case VAR_SAMP:
-		case SUM:
-			return true;
-		}
-		return false;
-	}
-
-    public String toString() {
+	public String toString() {
         return "RuleRemoveOptionalJoins"; //$NON-NLS-1$
     }
 

Modified: trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -222,7 +222,6 @@
 		TempMetadataStore result = resolveCommand(currentCommand, metadata, false);
 		if (replaceBindings && symbolMap != null && !symbolMap.isEmpty()) {
 			ExpressionMappingVisitor emv = new ExpressionMappingVisitor(symbolMap);
-			emv.setClone(true);
 			DeepPostOrderNavigator.doVisit(currentCommand, emv);
 		}
 		return result;

Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -55,6 +55,7 @@
 import org.teiid.core.util.Assertion;
 import org.teiid.core.util.TimestampWithTimezone;
 import org.teiid.language.SQLConstants.NonReserved;
+import org.teiid.metadata.FunctionMethod.Determinism;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.eval.Evaluator;
 import org.teiid.query.function.FunctionDescriptor;
@@ -62,6 +63,7 @@
 import org.teiid.query.function.FunctionMethods;
 import org.teiid.query.metadata.QueryMetadataInterface;
 import org.teiid.query.metadata.TempMetadataAdapter;
+import org.teiid.query.metadata.TempMetadataID;
 import org.teiid.query.metadata.TempMetadataStore;
 import org.teiid.query.optimizer.relational.rules.NewCalculateCostUtil;
 import org.teiid.query.optimizer.relational.rules.RuleMergeCriteria;
@@ -159,6 +161,8 @@
 import org.teiid.query.sql.visitor.ElementCollectorVisitor;
 import org.teiid.query.sql.visitor.EvaluatableVisitor;
 import org.teiid.query.sql.visitor.ExpressionMappingVisitor;
+import org.teiid.query.sql.visitor.FunctionCollectorVisitor;
+import org.teiid.query.sql.visitor.ValueIteratorProviderCollectorVisitor;
 import org.teiid.query.sql.visitor.EvaluatableVisitor.EvaluationLevel;
 import org.teiid.query.util.CommandContext;
 import org.teiid.query.validator.UpdateValidator.UpdateInfo;
@@ -685,6 +689,8 @@
 				continue;
 			}
 			if (plannedResult.query.getCorrelatedReferences() == null) {
+				//create the correlated refs if they exist
+				//there is a little bit of a design problem here that null usually means no refs.
 				ArrayList<Reference> correlatedReferences = new ArrayList<Reference>();
 				CorrelatedReferenceCollectorVisitor.collectReferences(plannedResult.query, groups, correlatedReferences);
 				if (!correlatedReferences.isEmpty()) {
@@ -695,26 +701,30 @@
 		            plannedResult.query.setCorrelatedReferences(map);
 		        }	
 			}
-			if (!rmc.planQuery(groups, true, plannedResult)) {
+			boolean requiresDistinct = requiresDistinctRows(query);
+			if (!rmc.planQuery(groups, requiresDistinct, plannedResult)) {
 				continue;
 			}
-			HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
-			if (query.getFrom().getClauses().size() > 1) {
-				continue;
+			if (requiresDistinct) {
+				//check for key preservation
+				HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
+				ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
+				if (!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups, metadata, true)) {
+					//if not key perserved then the semi-join will not remain in tact
+					continue;
+				}
 			}
-			ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
-			if (!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups, metadata, true)) {
-				continue;
-			}
 			crits.remove();
 			
 			GroupSymbol viewName = RulePlaceAccess.recontextSymbol(new GroupSymbol("X"), names); //$NON-NLS-1$
+			viewName.setName(viewName.getCanonicalName());
+			viewName.setDefinition(null);
 			Query q = createInlineViewQuery(viewName, plannedResult.query, metadata, plannedResult.query.getSelect().getProjectedSymbols());
 			
-			Iterator iter = q.getSelect().getProjectedSymbols().iterator();
+			Iterator<SingleElementSymbol> iter = q.getSelect().getProjectedSymbols().iterator();
 		    HashMap<Expression, SingleElementSymbol> expressionMap = new HashMap<Expression, SingleElementSymbol>();
-		    for (SingleElementSymbol symbol : (List<SingleElementSymbol>)plannedResult.query.getSelect().getProjectedSymbols()) {
-		        expressionMap.put(SymbolMap.getExpression(symbol), (SingleElementSymbol)iter.next());
+		    for (SingleElementSymbol symbol : plannedResult.query.getSelect().getProjectedSymbols()) {
+		        expressionMap.put(SymbolMap.getExpression(symbol), iter.next());
 		    }
 			for (int i = 0; i < plannedResult.leftExpressions.size(); i++) {
 				plannedResult.nonEquiJoinCriteria.add(new CompareCriteria(SymbolMap.getExpression((Expression)plannedResult.leftExpressions.get(i)), CompareCriteria.EQ, (Expression)plannedResult.rightExpressions.get(i)));
@@ -729,6 +739,32 @@
 		query.setCriteria(Criteria.combineCriteria(query.getCriteria(), Criteria.combineCriteria(current)));
 	}
 
+	private boolean requiresDistinctRows(Query query) {
+		Set<AggregateSymbol> aggs = new HashSet<AggregateSymbol>();
+		aggs.addAll(AggregateSymbolCollectorVisitor.getAggregates(query.getSelect(), false));
+		aggs.addAll(AggregateSymbolCollectorVisitor.getAggregates(query.getHaving(), false));
+		if (!aggs.isEmpty() || query.getGroupBy() != null) {
+			if (!AggregateSymbol.areAggregatesCardinalityDependent(aggs)) {
+				return false;
+			}
+		} else if (query.getSelect().isDistinct()) {
+			for (SingleElementSymbol projectSymbol : query.getSelect().getProjectedSymbols()) {
+				Expression ex = SymbolMap.getExpression(projectSymbol);
+	            Collection<Function> functions = FunctionCollectorVisitor.getFunctions(ex, true, false);
+	           	for (Function function : functions) {
+	           		if ( function.getFunctionDescriptor().getDeterministic() == Determinism.NONDETERMINISTIC) {
+	           			return true;
+	           		}
+	            }
+	           	if (!ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(ex).isEmpty()) {
+	           		return true;
+	           	}
+			}
+			return false;
+		}
+		return true;
+	}
+
 	/**
 	 * Converts a group by with expressions into a group by with only element symbols and an inline view
 	 * @param query
@@ -792,10 +828,10 @@
         } catch (TeiidException err) {
             throw new TeiidRuntimeException(err);
         }
-        Iterator iter = outerQuery.getSelect().getProjectedSymbols().iterator();
+        Iterator<SingleElementSymbol> iter = outerQuery.getSelect().getProjectedSymbols().iterator();
         HashMap<Expression, SingleElementSymbol> expressionMap = new HashMap<Expression, SingleElementSymbol>();
-        for (SingleElementSymbol symbol : (List<SingleElementSymbol>)query.getSelect().getProjectedSymbols()) {
-            expressionMap.put(SymbolMap.getExpression(symbol), (SingleElementSymbol)iter.next());
+        for (SingleElementSymbol symbol : query.getSelect().getProjectedSymbols()) {
+            expressionMap.put(SymbolMap.getExpression(symbol), iter.next());
         }
         ExpressionMappingVisitor.mapExpressions(groupBy, expressionMap);
         outerQuery.setGroupBy(groupBy);
@@ -819,7 +855,7 @@
 			return false;
 		}
 		HashSet<Expression> selectExpressions = new HashSet<Expression>();
-		for (SingleElementSymbol selectExpr : (List<SingleElementSymbol>)query.getSelect().getProjectedSymbols()) {
+		for (SingleElementSymbol selectExpr : query.getSelect().getProjectedSymbols()) {
 			selectExpressions.add(SymbolMap.getExpression(selectExpr));
 		}
 		for (SingleElementSymbol groupByExpr :  (List<SingleElementSymbol>)groupBy.getSymbols()) {
@@ -873,7 +909,7 @@
             return queryCommand;
         }
         Select select = queryCommand.getProjectedQuery().getSelect();
-        final List projectedSymbols = select.getProjectedSymbols();
+        final List<SingleElementSymbol> projectedSymbols = select.getProjectedSymbols();
         
         LinkedList<OrderByItem> unrelatedItems = new LinkedList<OrderByItem>();
         
@@ -904,10 +940,10 @@
         
         try {
         	top = createInlineViewQuery(new GroupSymbol("X"), query, metadata, select.getProjectedSymbols()); //$NON-NLS-1$
-			Iterator iter = top.getSelect().getProjectedSymbols().iterator();
+			Iterator<SingleElementSymbol> iter = top.getSelect().getProjectedSymbols().iterator();
 		    HashMap<Expression, SingleElementSymbol> expressionMap = new HashMap<Expression, SingleElementSymbol>();
-		    for (SingleElementSymbol symbol : (List<SingleElementSymbol>)select.getProjectedSymbols()) {
-		    	SingleElementSymbol ses = (SingleElementSymbol)iter.next();
+		    for (SingleElementSymbol symbol : select.getProjectedSymbols()) {
+		    	SingleElementSymbol ses = iter.next();
 		        expressionMap.put(SymbolMap.getExpression(symbol), ses);
 		        expressionMap.put(new ElementSymbol(symbol.getName()), ses);
 		    }
@@ -2739,8 +2775,8 @@
 	        Query firstProject = ((QueryCommand)nested).getProjectedQuery(); 
 	        makeSelectUnique(firstProject.getSelect(), false);
         }
-        store.addTempGroup(inlineGroup.getName(), nested.getProjectedSymbols());
-        inlineGroup.setMetadataID(store.getTempGroupID(inlineGroup.getName()));
+        TempMetadataID gid = store.addTempGroup(inlineGroup.getName(), nested.getProjectedSymbols());
+        inlineGroup.setMetadataID(gid);
         
         List<Class<?>> actualTypes = new ArrayList<Class<?>>(nested.getProjectedSymbols().size());
         for (SingleElementSymbol ses : actualSymbols) {

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/Select.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/Select.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/Select.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -22,12 +22,22 @@
 
 package org.teiid.query.sql.lang;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
 
 import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.core.util.HashCodeUtil;
-import org.teiid.query.sql.*;
-import org.teiid.query.sql.symbol.*;
+import org.teiid.query.sql.LanguageObject;
+import org.teiid.query.sql.LanguageVisitor;
+import org.teiid.query.sql.symbol.AllInGroupSymbol;
+import org.teiid.query.sql.symbol.AllSymbol;
+import org.teiid.query.sql.symbol.ElementSymbol;
+import org.teiid.query.sql.symbol.GroupSymbol;
+import org.teiid.query.sql.symbol.MultipleElementSymbol;
+import org.teiid.query.sql.symbol.SelectSymbol;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
 import org.teiid.query.sql.visitor.SQLStringVisitor;
 
 
@@ -200,15 +210,15 @@
 	 * single column.
 	 * @return Ordered list of SingleElementSymbol
 	 */
-	public List getProjectedSymbols() { 
-		ArrayList projectedSymbols = new ArrayList();
+	public List<SingleElementSymbol> getProjectedSymbols() { 
+		ArrayList<SingleElementSymbol> projectedSymbols = new ArrayList<SingleElementSymbol>();
 		Iterator iter = symbols.iterator();
 		while(iter.hasNext()) {
 			SelectSymbol symbol = (SelectSymbol) iter.next();
 			if(symbol instanceof SingleElementSymbol) { 
-				projectedSymbols.add(symbol);
+				projectedSymbols.add((SingleElementSymbol)symbol);
 			} else {
-			    List multiSymbols = ((MultipleElementSymbol)symbol).getElementSymbols();
+			    List<ElementSymbol> multiSymbols = ((MultipleElementSymbol)symbol).getElementSymbols();
 			    if(multiSymbols != null) { 
 			        projectedSymbols.addAll(multiSymbols);
 			    }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -22,6 +22,7 @@
 
 package org.teiid.query.sql.symbol;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -244,5 +245,31 @@
                && EquivalenceUtil.areEqual(this.getExpression(), other.getExpression())
         	   && EquivalenceUtil.areEqual(this.getOrderBy(), other.getOrderBy());
     }
+    
+    public boolean isCardinalityDependent() {
+    	if (isDistinct()) {
+    		return false;
+    	}
+    	switch (getAggregateFunction()) {
+		case COUNT:
+		case AVG:
+		case STDDEV_POP:
+		case STDDEV_SAMP:
+		case VAR_POP:
+		case VAR_SAMP:
+		case SUM:
+			return true;
+		}
+		return false;
+    }
 
+	public static boolean areAggregatesCardinalityDependent(Collection<AggregateSymbol> aggs) {
+		for (AggregateSymbol aggregateSymbol : aggs) {
+			if (aggregateSymbol.isCardinalityDependent()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -24,6 +24,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 
 import org.teiid.query.sql.LanguageObject;
@@ -98,6 +99,9 @@
     }
 
     public static final Collection<AggregateSymbol> getAggregates(LanguageObject obj, boolean removeDuplicates) {
+    	if (obj == null) {
+    		return Collections.emptyList();
+    	}
         Collection<AggregateSymbol> aggregates = null;
         if (removeDuplicates) {
             aggregates = new HashSet<AggregateSymbol>();

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -77,7 +77,7 @@
 public class ExpressionMappingVisitor extends LanguageVisitor {
 
     private Map symbolMap;
-    private boolean clone;
+    private boolean clone = true;
 
     /**
      * Constructor for ExpressionMappingVisitor.

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java	2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java	2011-03-19 01:18:44 UTC (rev 3009)
@@ -754,8 +754,26 @@
         ProcessorPlan plan = helpPlan("Select e1, (select e1 FROM pm2.g1 where e1 = 'x') from pm1.g1", FakeMetadataFactory.example1Cached(),  //$NON-NLS-1$
             new String[] { "SELECT g_0.e1, (SELECT g_0.e1 FROM pm2.g1 AS g_0 WHERE g_0.e1 = 'x') FROM pm1.g1 AS g_0" }, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
         checkNodeTypes(plan, FULL_PUSHDOWN); 
-    }   
+    }
     
+    @Test public void testSubqueryRewriteToJoinDistinct() throws Exception {
+        TestQueryRewriter.helpTestRewriteCommand("Select distinct e1 from pm1.g1 as x where exists (select pm1.g1.e1 FROM pm1.g1 where e1 = x.e1)", "SELECT DISTINCT e1 FROM pm1.g1 AS x, (SELECT pm1.g1.e1 FROM pm1.g1) AS X__1 WHERE x.e1 = X__1.e1", FakeMetadataFactory.example1Cached());
+    }
+    
+    /**
+     * Agg does not depend on cardinality
+     */
+    @Test public void testSubqueryRewriteToJoinGroupBy() throws Exception {
+        TestQueryRewriter.helpTestRewriteCommand("Select max(e1) from pm1.g1 as x where exists (select pm1.g1.e1 FROM pm1.g1 where e1 = x.e1) group by e2", "SELECT MAX(e1) FROM pm1.g1 AS x, (SELECT pm1.g1.e1 FROM pm1.g1) AS X__1 WHERE x.e1 = X__1.e1 GROUP BY e2", FakeMetadataFactory.example1Cached());
+    }
+    
+    /**
+     * Agg does depend on cardinality
+     */
+    @Test public void testSubqueryRewriteToJoinGroupBy1() throws Exception {
+        TestQueryRewriter.helpTestRewriteCommand("Select avg(e1) from pm1.g1 as x where exists (select pm1.g1.e1 FROM pm1.g1 where e1 = x.e1) group by e2", "SELECT AVG(e1) FROM pm1.g1 AS x WHERE EXISTS (SELECT pm1.g1.e1 FROM pm1.g1 WHERE e1 = x.e1 LIMIT 1) GROUP BY e2", FakeMetadataFactory.example1Cached());
+    }
+    
     @Test public void testSubqueryRewriteToJoin() throws Exception {
         TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where exists (select pm1.g1.e1 FROM pm1.g1 where e1 = pm3.g1.e1)", "SELECT e1 FROM pm3.g1, (SELECT pm1.g1.e1 FROM pm1.g1) AS X__1 WHERE pm3.g1.e1 = X__1.e1", FakeMetadataFactory.example4());
     }



More information about the teiid-commits mailing list