[teiid-commits] teiid SVN: r4307 - in trunk: api/src/main/java/org/teiid/language/visitor and 22 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Fri Aug 10 10:52:39 EDT 2012


Author: shawkins
Date: 2012-08-10 10:52:39 -0400 (Fri, 10 Aug 2012)
New Revision: 4307

Added:
   trunk/api/src/main/java/org/teiid/language/Array.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/Array.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/ArrayValue.java
   trunk/engine/src/test/java/org/teiid/query/sql/symbol/TestArray.java
Modified:
   trunk/api/src/main/java/org/teiid/language/visitor/AbstractLanguageVisitor.java
   trunk/api/src/main/java/org/teiid/language/visitor/LanguageObjectVisitor.java
   trunk/api/src/main/java/org/teiid/language/visitor/SQLStringVisitor.java
   trunk/api/src/main/java/org/teiid/translator/BaseDelegatingExecutionFactory.java
   trunk/api/src/main/java/org/teiid/translator/ExecutionFactory.java
   trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html
   trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/h2/H2ExecutionFactory.java
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/oracle/OracleExecutionFactory.java
   trunk/connectors/translator-jdbc/src/test/java/org/teiid/translator/jdbc/oracle/TestOracleTranslator.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/CapabilitiesConverter.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java
   trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/capabilities/SourceCapabilities.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanProcedures.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentCriteriaProcessor.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentProcedureCriteriaProcessor.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/TupleSourceValueIterator.java
   trunk/engine/src/main/java/org/teiid/query/sql/LanguageVisitor.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/SubqueryCompareCriteria.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java
   trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/ContextReference.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/Reference.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/ScalarSubquery.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
   trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestDependentJoins.java
   trunk/engine/src/test/java/org/teiid/query/processor/TestDependentJoins.java
   trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestExpressionMappingVisitor.java
   trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java
Log:
TEIID-2036 added support for array comparisons in multi-attribute dependent joins.

Added: trunk/api/src/main/java/org/teiid/language/Array.java
===================================================================
--- trunk/api/src/main/java/org/teiid/language/Array.java	                        (rev 0)
+++ trunk/api/src/main/java/org/teiid/language/Array.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -0,0 +1,62 @@
+/*
+ * 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 org.teiid.language;
+
+import java.util.List;
+
+import org.teiid.language.visitor.LanguageObjectVisitor;
+import org.teiid.translator.TypeFacility;
+
+public class Array implements Expression {
+
+	private Class<?> baseType;
+	private List<Expression> expressions;
+	
+	public Array(Class<?> baseType, List<Expression> expresssions) {
+		this.baseType = baseType;
+		this.expressions = expresssions;
+	}
+	
+	@Override
+	public Class<?> getType() {
+		return TypeFacility.RUNTIME_TYPES.OBJECT;
+	}
+
+	@Override
+	public void acceptVisitor(LanguageObjectVisitor visitor) {
+		visitor.visit(this);
+	}
+	
+	public Class<?> getBaseType() {
+		return baseType;
+	}
+	
+	public void setBaseType(Class<?> baseType) {
+		this.baseType = baseType;
+	}
+	
+	public List<Expression> getExpressions() {
+		return expressions;
+	}
+
+}


Property changes on: trunk/api/src/main/java/org/teiid/language/Array.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/api/src/main/java/org/teiid/language/visitor/AbstractLanguageVisitor.java
===================================================================
--- trunk/api/src/main/java/org/teiid/language/visitor/AbstractLanguageVisitor.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/api/src/main/java/org/teiid/language/visitor/AbstractLanguageVisitor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -121,4 +121,6 @@
     public void visit(With obj) {}
     @Override
     public void visit(WithItem obj) {}
+    @Override
+    public void visit(Array array) {}
 }

Modified: trunk/api/src/main/java/org/teiid/language/visitor/LanguageObjectVisitor.java
===================================================================
--- trunk/api/src/main/java/org/teiid/language/visitor/LanguageObjectVisitor.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/api/src/main/java/org/teiid/language/visitor/LanguageObjectVisitor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -66,4 +66,5 @@
 	public void visit(WindowFunction windowFunction);
 	public void visit(WindowSpecification windowSpecification);
 	public void visit(Parameter obj);
+	public void visit(Array array);
 }

Modified: trunk/api/src/main/java/org/teiid/language/visitor/SQLStringVisitor.java
===================================================================
--- trunk/api/src/main/java/org/teiid/language/visitor/SQLStringVisitor.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/api/src/main/java/org/teiid/language/visitor/SQLStringVisitor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -160,9 +160,13 @@
         buffer.append(Tokens.SPACE);
         buffer.append(obj.getOperator());
         buffer.append(Tokens.SPACE);
-        append(obj.getRightExpression());
+        appendRightComparison(obj);
     }
 
+	protected void appendRightComparison(Comparison obj) {
+		append(obj.getRightExpression());
+	}
+
     public void visit(AndOr obj) {
         String opString = obj.getOperator().toString();
 
@@ -942,6 +946,13 @@
     	}
     	buffer.append(Tokens.RPAREN);    	
     }
+    
+    @Override
+    public void visit(Array array) {
+    	buffer.append(Tokens.LPAREN);
+    	append(array.getExpressions());
+    	buffer.append(Tokens.RPAREN);
+    }
  
     /**
      * Gets the SQL string representation for a given LanguageObject.

Modified: trunk/api/src/main/java/org/teiid/translator/BaseDelegatingExecutionFactory.java
===================================================================
--- trunk/api/src/main/java/org/teiid/translator/BaseDelegatingExecutionFactory.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/api/src/main/java/org/teiid/translator/BaseDelegatingExecutionFactory.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -447,4 +447,8 @@
 	public boolean isForkable() {
 		return delegate.isForkable();
 	}
+	@Override
+	public boolean supportsArrayType() {
+		return delegate.supportsArrayType();
+	}
 }

Modified: trunk/api/src/main/java/org/teiid/translator/ExecutionFactory.java
===================================================================
--- trunk/api/src/main/java/org/teiid/translator/ExecutionFactory.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/api/src/main/java/org/teiid/translator/ExecutionFactory.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -1027,5 +1027,13 @@
 	public boolean isForkable() {
 		return true;
 	}
+	
+	/**
+	 * The engine currently uses array types for dependent joins.
+	 * @return true if an array type is supported.
+	 */
+	public boolean supportsArrayType() {
+		return false;
+	}
 
 }

Modified: trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html	2012-08-10 14:52:39 UTC (rev 4307)
@@ -34,6 +34,7 @@
   <LI>TEIID-2077 <B>Result reuse</B> - the engine will automatically detect if the same source query is used multiple times in a plan and reuse the result rather than issuing another query.
   <LI>TEIID-2113 <B>Misc parser improvements</B> - the parser will now accept the LATERAL keyword for defining a LATERAL join (previously we just used the TABLE keyword), unary negation is now supported e.g. -col1, the FOR keyword is optional for TEXTAGG,
 and the BNF documentation was dramatically improved. 
+  <LI>TEIID-2036 <B>Dependent Join Array Comparison</B> - platforms supporting array comparisons can have multi-attribute dependent joins pushed down as array comparisons.  Oracle and H2 translators are already marked as supporting array types.
 </UL>
 
 <h2><a name="Compatibility">Compatibility Issues</a></h2>

Modified: trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -901,7 +901,8 @@
 		}
 		return !(type == DataTypeManager.DefaultDataClasses.BIG_DECIMAL
 				|| type == DataTypeManager.DefaultDataClasses.BLOB
-				|| type == DataTypeManager.DefaultDataClasses.CLOB);
+				|| type == DataTypeManager.DefaultDataClasses.CLOB
+				|| type == DataTypeManager.DefaultDataClasses.OBJECT);
 	}
 
 }

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/h2/H2ExecutionFactory.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/h2/H2ExecutionFactory.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/h2/H2ExecutionFactory.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -210,4 +210,9 @@
     public String getLikeRegexString() {
     	return "REGEXP"; //$NON-NLS-1$
     }
+    
+    @Override
+    public boolean supportsArrayType() {
+    	return true;
+    }
 }

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/oracle/OracleExecutionFactory.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/oracle/OracleExecutionFactory.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/oracle/OracleExecutionFactory.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -506,6 +506,18 @@
     			}
     			super.visit(obj);
     		}
+    		
+    		@Override
+    		protected void appendRightComparison(Comparison obj) {
+    			if (obj.getRightExpression() instanceof Array) {
+    				//oracle needs rhs arrays nested in extra parens
+    				buffer.append(SQLConstants.Tokens.LPAREN);
+        			super.appendRightComparison(obj);
+        			buffer.append(SQLConstants.Tokens.RPAREN);
+    			} else {
+    				super.appendRightComparison(obj);
+    			}
+    		}
 
 			private boolean isChar(Expression obj) {
 				if (!(obj instanceof ColumnReference)) {
@@ -738,4 +750,9 @@
     	return OracleFormatFunctionModifier.supportsLiteral(literal);
     }
     
+    @Override
+    public boolean supportsArrayType() {
+    	return true;
+    }
+    
 }

Modified: trunk/connectors/translator-jdbc/src/test/java/org/teiid/translator/jdbc/oracle/TestOracleTranslator.java
===================================================================
--- trunk/connectors/translator-jdbc/src/test/java/org/teiid/translator/jdbc/oracle/TestOracleTranslator.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/connectors/translator-jdbc/src/test/java/org/teiid/translator/jdbc/oracle/TestOracleTranslator.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -41,6 +41,7 @@
 import org.teiid.core.util.UnitTestUtil;
 import org.teiid.dqp.internal.datamgr.ExecutionContextImpl;
 import org.teiid.dqp.internal.datamgr.FakeExecutionContextImpl;
+import org.teiid.language.Array;
 import org.teiid.language.Command;
 import org.teiid.language.Comparison;
 import org.teiid.language.Literal;
@@ -59,6 +60,7 @@
 import org.teiid.query.unittest.RealMetadataFactory;
 import org.teiid.translator.ExecutionContext;
 import org.teiid.translator.TranslatorException;
+import org.teiid.translator.TypeFacility;
 import org.teiid.translator.jdbc.JDBCProcedureExecution;
 import org.teiid.translator.jdbc.JDBCQueryExecution;
 import org.teiid.translator.jdbc.SQLConversionVisitor;
@@ -955,5 +957,18 @@
         Command obj = commandBuilder.getCommand(input, true, true);
         TranslationHelper.helpTestVisitor(output, TRANSLATOR, obj);
     }
+    
+    @Test public void testArrayComparison() throws Exception {
+        String input = "select intkey from bqt1.smalla where intkey = 5"; //$NON-NLS-1$
+        String output = "SELECT g_0.IntKey FROM SmallA g_0 WHERE (g_0.IntKey, g_0.IntKey) = ((5, 2))"; //$NON-NLS-1$
+               
+		CommandBuilder commandBuilder = new CommandBuilder(RealMetadataFactory.exampleBQTCached());
+        Select obj = (Select)commandBuilder.getCommand(input, true, true);
+        Comparison comp = (Comparison)obj.getWhere();
+        //modify to an array comparison, since there is not yet parsing support
+        comp.setLeftExpression(new Array(comp.getLeftExpression().getType(), Arrays.asList(comp.getLeftExpression(), comp.getLeftExpression())));
+        comp.setRightExpression(new Array(comp.getLeftExpression().getType(), Arrays.asList(comp.getRightExpression(), new Literal(2, TypeFacility.RUNTIME_TYPES.INTEGER))));
+        TranslationHelper.helpTestVisitor(output, TRANSLATOR, obj);
+    }
 
 }

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/CapabilitiesConverter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/CapabilitiesConverter.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/CapabilitiesConverter.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -113,6 +113,7 @@
         tgtCaps.setCapabilitySupport(Capability.CRITERIA_ONLY_LITERAL_COMPARE, srcCaps.supportsOnlyLiteralComparison());
         tgtCaps.setCapabilitySupport(Capability.DEPENDENT_JOIN, srcCaps.supportsDependentJoins());
         tgtCaps.setCapabilitySupport(Capability.CRITERIA_ON_SUBQUERY, srcCaps.supportsSubqueryInOn());
+        tgtCaps.setCapabilitySupport(Capability.ARRAY_TYPE, srcCaps.supportsArrayType());
         
         List<String> functions = srcCaps.getSupportedFunctions();
         if(functions != null && functions.size() > 0) {

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -32,6 +32,7 @@
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
 import org.teiid.core.TeiidRuntimeException;
+import org.teiid.core.types.DataTypeManager;
 import org.teiid.language.*;
 import org.teiid.language.DerivedColumn;
 import org.teiid.language.Select;
@@ -56,6 +57,7 @@
 import org.teiid.query.sql.lang.SetQuery;
 import org.teiid.query.sql.lang.Update;
 import org.teiid.query.sql.symbol.*;
+import org.teiid.query.sql.symbol.Array;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.symbol.Function;
 import org.teiid.query.sql.symbol.ScalarSubquery;
@@ -416,10 +418,7 @@
 
     Condition translate(SetCriteria criteria) {
         Collection expressions = criteria.getValues();
-        List<org.teiid.language.Expression> translatedExpressions = new ArrayList<org.teiid.language.Expression>();
-        for (Iterator i = expressions.iterator(); i.hasNext();) {
-            translatedExpressions.add(translate((Expression)i.next()));
-        }
+        List<org.teiid.language.Expression> translatedExpressions = translateExpressionList(expressions);
         org.teiid.language.Expression expr = translate(criteria.getExpression());
         if (convertIn) {
         	Condition condition = null;
@@ -545,10 +544,16 @@
         	return translate((Criteria)expr);
         } else if (expr instanceof WindowFunction) {
         	return translate((WindowFunction)expr);
+        } else if (expr instanceof Array) {
+        	return translate((Array)expr);
         }
         throw new AssertionError();
     }
     
+    org.teiid.language.Array translate(Array array) {
+    	return new org.teiid.language.Array(array.getBaseType(), translateExpressionList(array.getExpressions()));
+    }
+    
     org.teiid.language.WindowFunction translate(WindowFunction windowFunction) {
     	org.teiid.language.WindowFunction result = new org.teiid.language.WindowFunction();
     	result.setFunction(translate(windowFunction.getFunction()));
@@ -556,17 +561,23 @@
     	ws.setOrderBy(translate(windowFunction.getWindowSpecification().getOrderBy(), false));
     	List<Expression> partition = windowFunction.getWindowSpecification().getPartition();
     	if (partition != null) {
-	    	ArrayList<org.teiid.language.Expression> partitionList = new ArrayList<org.teiid.language.Expression>(partition.size());
-	    	for (Expression ex : partition) {
-	    		partitionList.add(translate(ex));
-	    	}
+	    	ArrayList<org.teiid.language.Expression> partitionList = translateExpressionList(partition);
 	    	ws.setPartition(partitionList);
     	}
     	result.setWindowSpecification(ws);
     	return result;
     }
+
+	private ArrayList<org.teiid.language.Expression> translateExpressionList(
+			Collection<? extends Expression> list) {
+		ArrayList<org.teiid.language.Expression> result = new ArrayList<org.teiid.language.Expression>(list.size());
+		for (Expression ex : list) {
+			result.add(translate(ex));
+		}
+		return result;
+	}
     
-    org.teiid.language.Expression translate(Constant constant) {
+	org.teiid.language.Expression translate(Constant constant) {
     	if (constant.isMultiValued()) {
     		Parameter result = new Parameter();
     		result.setType(constant.getType());
@@ -575,6 +586,33 @@
     		result.setValueIndex(valueIndex++);
     		return result;
     	}
+    	if (constant.getValue() instanceof ArrayValue) {
+    		//TODO: we could check if there is a common base type (also needs to be in the dependent logic)
+    		// and expand binding options in the translators
+
+    		//we currently support the notion of a mixed type array, since we consider object a common base type
+    		//that will not work for all sources, so instead of treating this a single array (as commented out below),
+    		//we just turn it into an array of parameters
+    		//Literal result = new Literal(av.getValues(), org.teiid.language.Array.class);
+    		//result.setBindEligible(constant.isBindEligible());
+            //return result;
+
+    		ArrayValue av = (ArrayValue)constant.getValue();
+    		List<Constant> vals = new ArrayList<Constant>();
+    		Class<?> baseType = null;
+    		for (Object o : av.getValues()) {
+    			Constant c = new Constant(o);
+    			c.setBindEligible(constant.isBindEligible());
+    			vals.add(c);
+    			if (baseType == null) {
+    				baseType = c.getType();
+    			} else if (!baseType.equals(c.getType())) {
+					baseType = DataTypeManager.DefaultDataClasses.OBJECT;
+				}
+    		}
+    		return new org.teiid.language.Array(baseType, translateExpressionList(vals));
+    		
+    	}
         Literal result = new Literal(constant.getValue(), constant.getType());
         result.setBindEligible(constant.isBindEligible());
         return result;

Modified: trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -398,7 +398,7 @@
         	}
         	valueIter = new CollectionValueIterator(((SetCriteria)criteria).getValues());
         } else if (criteria instanceof DependentSetCriteria){
-        	ContextReference ref = (ContextReference)criteria;
+        	DependentSetCriteria ref = (DependentSetCriteria)criteria;
         	VariableContext vc = getContext(criteria).getVariableContext();
     		ValueIteratorSource vis = (ValueIteratorSource)vc.getGlobalValue(ref.getContextSymbol());
     		Set<Object> values;
@@ -639,6 +639,17 @@
 		   return evaluateQueryString(tuple, (QueryString)expression);
 	   } else if (expression instanceof XMLParse){
 		   return evaluateXMLParse(tuple, (XMLParse)expression);
+	   } else if (expression instanceof Array) {
+		   Array array = (Array)expression;
+		   List<Expression> exprs = array.getExpressions();
+		   Object[] result = new Object[exprs.size()];
+		   for (int i = 0; i < exprs.size(); i++) {
+			   result[i] = internalEvaluate(exprs.get(i), tuple);
+			   if (result[i] == null) {
+				   return null; //TODO: this is a hack
+			   }
+		   }
+		   return new ArrayValue(result);
 	   } else {
 	        throw new TeiidComponentException(QueryPlugin.Event.TEIID30329, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30329, expression.getClass().getName()));
 	   }

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/capabilities/SourceCapabilities.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/capabilities/SourceCapabilities.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/capabilities/SourceCapabilities.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -331,7 +331,8 @@
         WINDOW_FUNCTION_DISTINCT_AGGREGATES("WindowDistinctAggregates"), //$NON-NLS-1$
         QUERY_ONLY_SINGLE_TABLE_GROUP_BY,
         ONLY_FORMAT_LITERALS,
-        CRITERIA_ON_SUBQUERY;
+        CRITERIA_ON_SUBQUERY,
+        ARRAY_TYPE;
         
         private final String toString;
         

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -143,7 +143,6 @@
         EST_CARDINALITY,     // Float represents the estimated cardinality (amount of rows) produced by this node
         EST_COL_STATS,
         EST_SELECTIVITY,     // Float that represents the selectivity of a criteria node
-        MAX_NDV,			 // The max NDV before the dependent join will be aborted
         
         // Tuple limit and offset
         MAX_TUPLE_LIMIT,     // Expression that evaluates to the max number of tuples generated

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -1324,7 +1324,7 @@
 				break;
 			}
 			case NodeConstants.Types.GROUP: {
-				if (rpsc.pushAcrossGroupBy(sourceNode, critNode, metadata, false)) {
+				if (rpsc.pushAcrossGroupBy(sourceNode, critNode, metadata, false, capFinder)) {
 					critNodes.add(critNode);
 					initialTargets.add(sourceNode.getFirstChild());
 				}

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -25,13 +25,13 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.api.exception.query.QueryPlannerException;
 import org.teiid.core.TeiidComponentException;
+import org.teiid.core.types.DataTypeManager.DefaultDataClasses;
 import org.teiid.query.analysis.AnalysisRecord;
 import org.teiid.query.metadata.QueryMetadataInterface;
 import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
@@ -44,6 +44,8 @@
 import org.teiid.query.optimizer.relational.rules.NewCalculateCostUtil.DependentCostAnalysis;
 import org.teiid.query.sql.lang.DependentSetCriteria;
 import org.teiid.query.sql.lang.JoinType;
+import org.teiid.query.sql.lang.DependentSetCriteria.AttributeComparison;
+import org.teiid.query.sql.symbol.Array;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.util.SymbolMap;
@@ -274,14 +276,9 @@
         // Create DependentValueSource and set on the independent side as this will feed the values
         joinNode.setProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE, id);
 
-        List<PlanNode> crits = getDependentCriteriaNodes(id, independentExpressions, dependentExpressions, isLeft?joinNode.getLastChild():joinNode.getFirstChild(), metadata, dca);
+        PlanNode crit = getDependentCriteriaNode(id, independentExpressions, dependentExpressions, isLeft?joinNode.getLastChild():joinNode.getFirstChild(), metadata, dca);
         
-        PlanNode newRoot = sourceNode;
-        
-        for (PlanNode crit : crits) {
-            newRoot.addAsParent(crit);
-            newRoot = crit;
-        }
+        sourceNode.addAsParent(crit);
               
         if (isLeft) {
             JoinUtil.swapJoinChildren(joinNode);
@@ -297,47 +294,92 @@
      * @throws QueryMetadataException 
      * @since 4.3
      */
-    private List<PlanNode> getDependentCriteriaNodes(String id, List independentExpressions,
-                                           List dependentExpressions, PlanNode indNode, QueryMetadataInterface metadata, DependentCostAnalysis dca) throws QueryMetadataException, TeiidComponentException {
+    private PlanNode getDependentCriteriaNode(String id, List<Expression> independentExpressions,
+                                           List<Expression> dependentExpressions, PlanNode indNode, QueryMetadataInterface metadata, DependentCostAnalysis dca) throws QueryMetadataException, TeiidComponentException {
         
-        List<PlanNode> result = new LinkedList<PlanNode>();
-        
         Float cardinality = null;
         
+        List<DependentSetCriteria.AttributeComparison> expressions = new ArrayList<DependentSetCriteria.AttributeComparison>(dependentExpressions.size());
+        
         for (int i = 0; i < dependentExpressions.size(); i++) {
-            Expression depExpr = (Expression) dependentExpressions.get(i);
-            Expression indepExpr = (Expression) independentExpressions.get(i);
-            DependentSetCriteria crit = new DependentSetCriteria(SymbolMap.getExpression(depExpr), id);
-            float ndv = NewCalculateCostUtil.UNKNOWN_VALUE;
-            Float maxNdv = null;
+            Expression depExpr = dependentExpressions.get(i);
+            Expression indExpr = independentExpressions.get(i);
+
+            DependentSetCriteria.AttributeComparison comp = new DependentSetCriteria.AttributeComparison();
             if (dca != null && dca.expectedNdv[i] != null) {
             	if (dca.expectedNdv[i] > 4*dca.maxNdv[i]) {
             		continue; //not necessary to use
             	}
-            	ndv = dca.expectedNdv[i];
-            	maxNdv = dca.maxNdv[i];
-            	crit.setMaxNdv(dca.maxNdv[i]);
+            	comp.ndv = dca.expectedNdv[i];
+            	comp.maxNdv = dca.maxNdv[i];
             } else { 
-	            Collection<ElementSymbol> elems = ElementCollectorVisitor.getElements(indepExpr, true);
-	            if (cardinality == null) {
-	            	cardinality = NewCalculateCostUtil.computeCostForTree(indNode, metadata);
-	            }
-	            ndv = NewCalculateCostUtil.getNDVEstimate(indNode, metadata, cardinality, elems, true);
+                Collection<ElementSymbol> elems = ElementCollectorVisitor.getElements(indExpr, true);
+                if (cardinality == null) {
+                	cardinality = NewCalculateCostUtil.computeCostForTree(indNode, metadata);
+                }
+                comp.ndv = NewCalculateCostUtil.getNDVEstimate(indNode, metadata, cardinality, elems, true);
             }
-            crit.setNdv(ndv);
-            crit.setValueExpression(indepExpr);
-            
-            PlanNode selectNode = RelationalPlanner.createSelectNode(crit, false);
-            
-            selectNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
-            if (maxNdv != null) {
-            	selectNode.setProperty(NodeConstants.Info.MAX_NDV, maxNdv);
-            }
-            result.add(selectNode);
+            comp.ind = indExpr;
+            comp.dep = SymbolMap.getExpression(depExpr);
+            expressions.add(comp);
         }
+
+        return createDependentSetNode(id, expressions);
+
+    }
+
+	static PlanNode createDependentSetNode(String id, List<DependentSetCriteria.AttributeComparison> expressions) {
+		DependentSetCriteria crit = createDependentSetCriteria(id, expressions);
+		
+        PlanNode selectNode = RelationalPlanner.createSelectNode(crit, false);
         
-        return result;
-    }
+        selectNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
+        return selectNode;
+	}
+
+	static DependentSetCriteria createDependentSetCriteria(String id, List<DependentSetCriteria.AttributeComparison> expressions) {
+		if (expressions.isEmpty()) {
+			return null;
+		}
+		
+		Expression indEx = null;
+        Expression depEx = null;
+        float maxNdv = NewCalculateCostUtil.UNKNOWN_VALUE;
+        float ndv = NewCalculateCostUtil.UNKNOWN_VALUE;
+        if (expressions.size() == 1) {
+        	AttributeComparison attributeComparison = expressions.get(0);
+			indEx = attributeComparison.ind;
+        	depEx = attributeComparison.dep;
+        	maxNdv = attributeComparison.maxNdv;
+        	ndv = attributeComparison.ndv;
+        } else {
+        	List<Expression> indExprs = new ArrayList<Expression>(expressions.size());
+        	List<Expression> depExprs = new ArrayList<Expression>(expressions.size());
+        	boolean unknown = false;
+        	for (DependentSetCriteria.AttributeComparison comp : expressions) {
+				indExprs.add(comp.ind);
+				depExprs.add(comp.dep);
+				if (comp.ndv == NewCalculateCostUtil.UNKNOWN_VALUE) {
+					ndv = NewCalculateCostUtil.UNKNOWN_VALUE;
+					maxNdv = NewCalculateCostUtil.UNKNOWN_VALUE;
+					unknown = true;
+				} else if (!unknown) {
+					ndv = Math.max(ndv, comp.ndv);
+		        	maxNdv = Math.max(maxNdv, comp.maxNdv);
+				}
+			}
+        	//TODO: detect a base type
+        	indEx = new Array(DefaultDataClasses.OBJECT, indExprs);
+        	depEx = new Array(DefaultDataClasses.OBJECT, depExprs);
+        }
+        
+        DependentSetCriteria crit = new DependentSetCriteria(depEx, id);
+        crit.setValueExpression(indEx);
+        crit.setAttributes(expressions);
+        crit.setMaxNdv(maxNdv);
+        crit.setNdv(ndv);
+		return crit;
+	}
     
     public String toString() {
         return "ChooseDependent"; //$NON-NLS-1$

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanProcedures.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanProcedures.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanProcedures.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -50,6 +50,7 @@
 import org.teiid.query.sql.lang.SPParameter;
 import org.teiid.query.sql.lang.SetCriteria;
 import org.teiid.query.sql.lang.StoredProcedure;
+import org.teiid.query.sql.lang.DependentSetCriteria.AttributeComparison;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.symbol.Reference;
@@ -185,9 +186,23 @@
                 }
                 
                 public void visit(DependentSetCriteria obj) {
-                    if (!obj.isNegated() && checkForInput(obj.getExpression())) {
-                        addInputNode((Reference)obj.getExpression());
+                    if (obj.isNegated()) {
+                    	return; //just a sanity check
                     }
+                	if (obj.hasMultipleAttributes()) {
+                		for (AttributeComparison comp : obj.getAttributes()) {
+                			if (!checkForInput(comp.dep)) {
+                				return;
+                			}
+                		}
+                		for (AttributeComparison comp : obj.getAttributes()) {
+                			params.add(((Reference)comp.dep).getExpression());
+                		}
+                		conjuncts.add(crit);
+                        NodeEditor.removeChildNode(currentNode.getParent(), currentNode);
+                	} else if (checkForInput(obj.getExpression())) {
+                		addInputNode((Reference)obj.getExpression());
+                	}
                 }
                 
                 boolean checkForInput(Expression expr) {
@@ -218,7 +233,9 @@
                 }
                 
             };
-            crit.acceptVisitor(visitor);
+            for (Criteria conjunct : Criteria.separateCriteriaByAnd(crit)) {
+                conjunct.acceptVisitor(visitor);
+            }
         }
     }
     

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -22,6 +22,8 @@
 
 package org.teiid.query.optimizer.relational.rules;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -37,6 +39,7 @@
 import org.teiid.query.analysis.AnalysisRecord;
 import org.teiid.query.metadata.QueryMetadataInterface;
 import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
+import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
 import org.teiid.query.optimizer.relational.OptimizerRule;
 import org.teiid.query.optimizer.relational.RuleStack;
 import org.teiid.query.optimizer.relational.plantree.NodeConstants;
@@ -47,8 +50,10 @@
 import org.teiid.query.resolver.util.AccessPattern;
 import org.teiid.query.sql.lang.CompoundCriteria;
 import org.teiid.query.sql.lang.Criteria;
+import org.teiid.query.sql.lang.DependentSetCriteria;
 import org.teiid.query.sql.lang.JoinType;
 import org.teiid.query.sql.lang.SubqueryContainer;
+import org.teiid.query.sql.lang.DependentSetCriteria.AttributeComparison;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.symbol.GroupSymbol;
@@ -56,6 +61,7 @@
 import org.teiid.query.sql.util.SymbolMap;
 import org.teiid.query.sql.visitor.AggregateSymbolCollectorVisitor;
 import org.teiid.query.sql.visitor.ElementCollectorVisitor;
+import org.teiid.query.sql.visitor.GroupsUsedByElementsVisitor;
 import org.teiid.query.sql.visitor.ValueIteratorProviderCollectorVisitor;
 import org.teiid.query.util.CommandContext;
 
@@ -111,19 +117,23 @@
                     deadNodes.add(critNode);
 	                continue;
 	            }
-	            pushTowardOriginatingNode(sourceNode, critNode, metadata, capFinder);
-	            
-                boolean moved = false;
+	            boolean moved = pushTowardOriginatingNode(sourceNode, critNode, metadata, capFinder);
                 
                 if(critNode.hasBooleanProperty(Info.IS_PUSHED) || (critNode.getGroups().isEmpty() && critNode.getSubqueryContainers().isEmpty()) || !atBoundary(critNode, sourceNode)) {
                     deadNodes.add(critNode);
+                    movedAnyNode |= moved;
                     continue;
                 }
                
                 switch (sourceNode.getType()) {
                     case NodeConstants.Types.SOURCE:
                     {
-                        moved = pushAcrossFrame(sourceNode, critNode, metadata);
+                        Boolean acrossFrame = pushAcrossFrame(sourceNode, critNode, metadata);
+                        if (acrossFrame != null) {
+                        	moved = acrossFrame;
+                        } else {
+                        	movedAnyNode = true; //new nodes created
+                        }
                         break;
                     }
                     case NodeConstants.Types.JOIN:
@@ -136,7 +146,7 @@
                     }
                     case NodeConstants.Types.GROUP:
                     {
-                    	moved = pushAcrossGroupBy(sourceNode, critNode, metadata, true);
+                    	moved = pushAcrossGroupBy(sourceNode, critNode, metadata, true, capFinder);
                     }
                 }
                 
@@ -152,24 +162,25 @@
 	}
 
 	boolean pushAcrossGroupBy(PlanNode sourceNode,
-			PlanNode critNode, QueryMetadataInterface metadata, boolean inPlan)
-			throws QueryPlannerException {
+			PlanNode critNode, QueryMetadataInterface metadata, boolean inPlan, CapabilitiesFinder capFinder)
+			throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
+		if (critNode.hasBooleanProperty(NodeConstants.Info.IS_HAVING)) {
+			return false;
+		}
 		boolean moved = false;
-		if (!critNode.hasBooleanProperty(NodeConstants.Info.IS_HAVING)) {
-			SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
-			FrameUtil.convertNode(critNode, null, null, symbolMap.asMap(), metadata, true);
-			if (inPlan) {
-				NodeEditor.removeChildNode(critNode.getParent(), critNode);
-			    sourceNode.getFirstChild().addAsParent(critNode);
+		SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
+		FrameUtil.convertNode(critNode, null, null, symbolMap.asMap(), metadata, true);
+		if (inPlan) {
+			NodeEditor.removeChildNode(critNode.getParent(), critNode);
+		    sourceNode.getFirstChild().addAsParent(critNode);
+		}
+		moved = true;
+		if (critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
+			PlanNode accessNode = NodeEditor.findParent(critNode, NodeConstants.Types.ACCESS);
+			if (accessNode != null) {
+				markDependent(critNode, accessNode, metadata, capFinder);
+				moved = false; //terminal position
 			}
-			moved = true;
-			if (critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
-				PlanNode accessNode = NodeEditor.findParent(critNode, NodeConstants.Types.ACCESS);
-				if (accessNode != null) {
-					markDependent(critNode, accessNode);
-					moved = false; //terminal position
-				}
-			}
 		}
 		return moved;
 	}
@@ -230,14 +241,13 @@
             if (jt == JoinType.JOIN_CROSS) {
                 joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_INNER);
             }
+            return moveCriteriaIntoOnClause(critNode, joinNode);
+        }
+        JoinType optimized = JoinUtil.optimizeJoinType(critNode, joinNode, metadata);
+        
+        if (optimized == JoinType.JOIN_INNER) {
             moveCriteriaIntoOnClause(critNode, joinNode);
-        } else {
-            JoinType optimized = JoinUtil.optimizeJoinType(critNode, joinNode, metadata);
-            
-            if (optimized == JoinType.JOIN_INNER) {
-                moveCriteriaIntoOnClause(critNode, joinNode);
-                return true; //return true since the join type has changed
-            }
+            return true; //return true since the join type has changed
         }
         return false;
     }
@@ -246,8 +256,10 @@
      * @param critNode
      * @param joinNode
      */
-    private void moveCriteriaIntoOnClause(PlanNode critNode,
+    private boolean moveCriteriaIntoOnClause(PlanNode critNode,
                                           PlanNode joinNode) {
+        NodeEditor.removeChildNode(critNode.getParent(), critNode);
+
         List joinCriteria = (List)joinNode.getProperty(NodeConstants.Info.JOIN_CRITERIA);
         Criteria criteria = (Criteria)critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
         
@@ -257,13 +269,52 @@
             joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, joinCriteria);
         }
         
-        if (!joinCriteria.contains(criteria)) {
-            joinCriteria.add(criteria);
-            if(critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
-                joinNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
-            }
+        if (joinCriteria.contains(criteria)) {
+        	return false;
         }
-        NodeEditor.removeChildNode(critNode.getParent(), critNode);
+        boolean moved = false;
+    	if(critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
+    		if (criteria instanceof DependentSetCriteria) {
+    			DependentSetCriteria dsc = (DependentSetCriteria)criteria;
+    			if (dsc.hasMultipleAttributes()) {
+    				//split the array based upon the join children.
+    				List<DependentSetCriteria.AttributeComparison> joinExprs = new ArrayList<DependentSetCriteria.AttributeComparison>();
+    				List<DependentSetCriteria.AttributeComparison> leftExprs = new ArrayList<DependentSetCriteria.AttributeComparison>();
+    				List<DependentSetCriteria.AttributeComparison> rightExprs = new ArrayList<DependentSetCriteria.AttributeComparison>();
+    				PlanNode leftJoinSource = FrameUtil.findJoinSourceNode(joinNode.getFirstChild());
+    				PlanNode rightJoinSource = FrameUtil.findJoinSourceNode(joinNode.getLastChild());
+    				for (int i = 0; i < dsc.getAttributes().size(); i++) {
+    					DependentSetCriteria.AttributeComparison comp = dsc.getAttributes().get(i);
+    					Set<GroupSymbol> groups = GroupsUsedByElementsVisitor.getGroups(comp.dep);
+    					if (leftJoinSource.getGroups().containsAll(groups)) {
+    						leftExprs.add(comp);
+    					} else if (rightJoinSource.getGroups().containsAll(groups)){
+    						rightExprs.add(comp);
+    					} else {
+    						joinExprs.add(comp);
+    					}
+    				}
+    				criteria = RuleChooseDependent.createDependentSetCriteria(dsc.getContextSymbol(), joinExprs);
+    				PlanNode left = RuleChooseDependent.createDependentSetNode(dsc.getContextSymbol(), leftExprs);
+    				if (left != null) {
+    					moved = true;
+    					joinNode.getFirstChild().addAsParent(left);
+    				}
+    				PlanNode right = RuleChooseDependent.createDependentSetNode(dsc.getContextSymbol(), rightExprs);
+    				if (right != null) {
+    					moved = true;
+    					joinNode.getLastChild().addAsParent(right);
+    				}
+    			}
+    		}
+    		if (criteria != null) {
+    			joinNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
+    		}
+        }
+    	if (criteria != null) {
+    		joinCriteria.add(criteria);
+    	}
+        return moved;
     }
 
     /**
@@ -275,7 +326,7 @@
      * @throws QueryMetadataException
      * @throws TeiidComponentException
      */
-    void pushTowardOriginatingNode(PlanNode sourceNode, PlanNode critNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder)
+    boolean pushTowardOriginatingNode(PlanNode sourceNode, PlanNode critNode, final QueryMetadataInterface metadata, final CapabilitiesFinder capFinder)
 		throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
 
     	boolean groupSelects = sourceNode.getParent().getType() == NodeConstants.Types.SELECT && sourceNode.getChildCount() == 0;
@@ -284,20 +335,76 @@
         while (sourceNode.getParent().getType() == NodeConstants.Types.SELECT) {
             sourceNode = sourceNode.getParent();
             if (sourceNode == critNode) {
-                return;
+                return false;
             }
         }
 
 		// See how far we can move it towards the SOURCE node
-		PlanNode destination = examinePath(critNode, sourceNode, metadata, capFinder);
+		final PlanNode destination = examinePath(critNode, sourceNode, metadata, capFinder);
+		boolean result = false;
+		if (createdNodes == null & destination.getType() == NodeConstants.Types.ACCESS && isDependentFinalDestination(critNode, destination)) {
+    		Criteria crit = (Criteria)critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
+    		if (isMultiAttributeDependentSet(crit)) {
+    			result = splitSet(critNode, new DependentNodeTest() {
+					
+					@Override
+					public boolean isValid(PlanNode copyNode) throws QueryMetadataException,
+							QueryPlannerException, TeiidComponentException {
+						return RuleRaiseAccess.canRaiseOverSelect(destination, metadata, capFinder, copyNode, null);
+					}
+				}, (DependentSetCriteria)crit, destination); 
+    		}
+		}
+		
         NodeEditor.removeChildNode(critNode.getParent(), critNode);
         destination.addAsParent(critNode);
         if (groupSelects && destination == sourceNode) {
         	//Help with the detection of composite keys in pushed criteria
         	RuleMergeCriteria.mergeChain(critNode, metadata);
         }
+        
+        return result;
 	}
+    
+    private interface DependentNodeTest {
+    	boolean isValid(PlanNode copyNode) throws QueryMetadataException, QueryPlannerException, TeiidComponentException;
+    }
 
+	private boolean splitSet(PlanNode critNode, DependentNodeTest test, DependentSetCriteria dscOrig, PlanNode destination)
+			throws QueryMetadataException, TeiidComponentException,
+			QueryPlannerException {
+		boolean result = false;
+		List<DependentSetCriteria> dscList = splitDependentSetCriteria(dscOrig);
+		List<DependentSetCriteria.AttributeComparison> pushable = new ArrayList<AttributeComparison>();
+		List<DependentSetCriteria.AttributeComparison> nonPushable = new ArrayList<AttributeComparison>();
+		for (DependentSetCriteria dsc : dscList) {
+			PlanNode copyNode = copyNode(critNode);
+			setCriteria(dsc, copyNode);
+			if (test.isValid(copyNode)) {
+				pushable.add(dsc.getAttributes().get(0));
+		   } else {
+		    	nonPushable.add(dsc.getAttributes().get(0));
+		    }
+		}
+		if (!pushable.isEmpty()) {
+			result = true; //signal that we should run again
+			if (nonPushable.isEmpty()) {
+				throw new AssertionError("should not be completely pushed"); //$NON-NLS-1$
+			}
+			setCriteria(RuleChooseDependent.createDependentSetCriteria(dscOrig.getContextSymbol(), nonPushable), critNode);
+			PlanNode copyNode = copyNode(critNode);
+			setCriteria(RuleChooseDependent.createDependentSetCriteria(dscOrig.getContextSymbol(), pushable), copyNode);
+			destination.addAsParent(copyNode); //it should be pushed in the next run
+		}
+		return result;
+	}
+
+	private void setCriteria(DependentSetCriteria dsc, PlanNode copyNode) {
+		copyNode.setProperty(NodeConstants.Info.SELECT_CRITERIA, dsc);
+		copyNode.getGroups().clear();
+		copyNode.addGroups(GroupsUsedByElementsVisitor.getGroups(dsc));
+	}
+
     /**
 	 * Examine the path from crit node to source node to determine how far down a node
 	 * can be pushed.
@@ -329,12 +436,10 @@
                     	satisfyAccessPatterns(critNode, currentNode);
                     }
 
-                    if (critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)
-                    		&& NodeEditor.findNodePreOrder(currentNode.getFirstChild(), NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE) == null) {
+                    if (isDependentFinalDestination(critNode, currentNode)) {
                         //once a dependent crit node is pushed, don't bother pushing it further into the command
                         //dependent access node will use this as an assumption for where dependent sets can appear in the command
-                        critNode.setProperty(NodeConstants.Info.IS_PUSHED, Boolean.TRUE);
-                        currentNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
+                    	markDependent(critNode,currentNode, metadata, capFinder);
                         return currentNode.getFirstChild();
                     } 
 				} catch(QueryMetadataException e) {
@@ -373,17 +478,45 @@
 		return sourceNode;
 	}
 
-	private void markDependent(PlanNode critNode, PlanNode accessNode) {
+	private boolean isMultiAttributeDependentSet(Criteria crit) {
+		return crit instanceof DependentSetCriteria && ((DependentSetCriteria)crit).hasMultipleAttributes();
+	}
+
+	private boolean isDependentFinalDestination(PlanNode critNode,
+			PlanNode currentNode) {
+		return critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)
+				&& NodeEditor.findNodePreOrder(currentNode.getFirstChild(), NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE) == null;
+	}
+
+	private void markDependent(PlanNode critNode, PlanNode accessNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException {
 		//once a dependent crit node is pushed, don't bother pushing it further into the command
 		//dependent access node will use this as an assumption for where dependent sets can appear in the command
 		critNode.setProperty(NodeConstants.Info.IS_PUSHED, Boolean.TRUE);
-		if (createdNodes == null) {
-			accessNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
+		if (createdNodes != null) {
+			return; //this is during a planning run and should not cause additional side-effects
 		}
+		accessNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
+		Criteria crit = (Criteria) critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
+		if (isMultiAttributeDependentSet(crit) 
+				&& !CapabilitiesUtil.supports(Capability.ARRAY_TYPE, RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata), metadata, capFinder)) {
+			//split the criteria into individual predicates
+			List<DependentSetCriteria> crits = splitDependentSetCriteria((DependentSetCriteria) crit);
+			critNode.setProperty(NodeConstants.Info.SELECT_CRITERIA, new CompoundCriteria(crits));
+		}
 	}
 
-	boolean pushAcrossFrame(PlanNode sourceNode, PlanNode critNode, QueryMetadataInterface metadata)
-		throws QueryPlannerException {
+	private List<DependentSetCriteria> splitDependentSetCriteria(DependentSetCriteria dsc) {
+		List<AttributeComparison> attributes = dsc.getAttributes();
+		List<DependentSetCriteria> crits = new ArrayList<DependentSetCriteria>(attributes.size());
+		for (int i = 0; i < attributes.size(); i++) {
+			DependentSetCriteria.AttributeComparison comp = attributes.get(i);
+			crits.add(RuleChooseDependent.createDependentSetCriteria(dsc.getContextSymbol(), Arrays.asList(comp)));
+		}
+		return crits;
+	}
+
+	Boolean pushAcrossFrame(PlanNode sourceNode, PlanNode critNode, QueryMetadataInterface metadata)
+		throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
         
         //ensure that the criteria can be pushed further
         if (sourceNode.getChildCount() == 1 && FrameUtil.isOrderedOrStrictLimit(sourceNode.getFirstChild())) {
@@ -427,26 +560,42 @@
 		return true;
 	}
 
-	boolean moveNodeAcrossFrame(PlanNode critNode, PlanNode sourceNode, QueryMetadataInterface metadata)
-		throws QueryPlannerException {
+	Boolean moveNodeAcrossFrame(PlanNode critNode, PlanNode sourceNode, final QueryMetadataInterface metadata)
+		throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
 
 	      // Check that sourceNode has a child to push across
         if(sourceNode.getChildCount() == 0) {
             return false;
         }
 
-        PlanNode projectNode = NodeEditor.findNodePreOrder(sourceNode.getFirstChild(), NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE);
+        final PlanNode projectNode = NodeEditor.findNodePreOrder(sourceNode.getFirstChild(), NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE);
         if(FrameUtil.isProcedure(projectNode)) {
             return false;
         }
         
-        SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
+        final SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
         
-        if (!createConvertedSelectNode(critNode, sourceNode.getGroups().iterator().next(), projectNode, symbolMap, metadata)) {
+        final GroupSymbol sourceGroup = sourceNode.getGroups().iterator().next();
+		if (!placeConvertedSelectNode(critNode, sourceGroup, projectNode, symbolMap, metadata)) {
+        	if (createdNodes == null) {
+        		Criteria crit = (Criteria)critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
+        		if (isMultiAttributeDependentSet(crit) && splitSet(critNode, new DependentNodeTest() {
+        					
+        					@Override
+        					public boolean isValid(PlanNode copyNode) throws QueryMetadataException,
+        							QueryPlannerException, TeiidComponentException {
+        						return createConvertedSelectNode(copyNode, sourceGroup, projectNode, symbolMap, metadata) != null;
+        					}
+        				}, (DependentSetCriteria)crit, sourceNode)) {
+        			return null;
+        		}
+        	}
             return false;
         }
 		
-        satisfyAccessPatterns(critNode, sourceNode);
+        if (createdNodes == null) {
+        	satisfyAccessPatterns(critNode, sourceNode);
+        }
         
 		// Mark critNode as a "phantom"
 		critNode.setProperty(NodeConstants.Info.IS_PHANTOM, Boolean.TRUE);
@@ -537,7 +686,9 @@
         // Find source node above union and grab the symbol map
         PlanNode sourceNode = NodeEditor.findParent(setOp, NodeConstants.Types.SOURCE);
         GroupSymbol virtualGroup = sourceNode.getGroups().iterator().next();
-        satisfyAccessPatterns(critNode, sourceNode);
+        if (createdNodes == null) {
+        	satisfyAccessPatterns(critNode, sourceNode);
+        }
         
         SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
         SymbolMap childMap = symbolMap;
@@ -557,7 +708,7 @@
 	        }
 		    
 			// Move the node
-			if(createConvertedSelectNode(critNode, virtualGroup, projectNode, childMap, metadata)) {
+			if(placeConvertedSelectNode(critNode, virtualGroup, projectNode, childMap, metadata)) {
                 movedCount++;
             }
 			
@@ -584,14 +735,32 @@
         }
 	}
 
-    private boolean createConvertedSelectNode(PlanNode critNode,
+    private boolean placeConvertedSelectNode(PlanNode critNode,
     							   GroupSymbol sourceGroup,
                                    PlanNode projectNode,
                                    SymbolMap symbolMap,
                                    QueryMetadataInterface metadata) throws QueryPlannerException {
-        // If projectNode has children, then it is from a SELECT without a FROM and the criteria should not be pushed
+        PlanNode copyNode = createConvertedSelectNode(critNode, sourceGroup,
+				projectNode, symbolMap, metadata);
+        if (copyNode == null) {
+        	return false;
+        }
+        
+        PlanNode intermediateParent = NodeEditor.findParent(projectNode, NodeConstants.Types.ACCESS, NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP);
+        if (intermediateParent != null) {
+            intermediateParent.addAsParent(copyNode);
+        } else {
+        	projectNode.getFirstChild().addAsParent(copyNode);
+        }
+		return true;
+    }
+
+	private PlanNode createConvertedSelectNode(PlanNode critNode,
+			GroupSymbol sourceGroup, PlanNode projectNode, SymbolMap symbolMap,
+			QueryMetadataInterface metadata) throws QueryPlannerException {
+		// If projectNode has children, then it is from a SELECT without a FROM and the criteria should not be pushed
         if(projectNode.getChildCount() == 0) {
-            return false;
+            return null;
         }
         List<WindowFunction> windowFunctions = null;
         if (projectNode.hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
@@ -603,12 +772,12 @@
         Boolean conversionResult = checkConversion(symbolMap, ElementCollectorVisitor.getElements(crit, true), windowFunctions);
         
         if (conversionResult == Boolean.FALSE) {
-        	return false; //not convertable
+        	return null; //not convertable
         }
         
         if (!critNode.getSubqueryContainers().isEmpty() 
         		&& checkConversion(symbolMap, critNode.getCorrelatedReferenceElements(), windowFunctions) != null) {
-    		return false; //not convertable, or has an aggregate for a correlated reference
+    		return null; //not convertable, or has an aggregate for a correlated reference
         }
         
         PlanNode copyNode = copyNode(critNode);
@@ -624,17 +793,10 @@
         	if (this.createdNodes != null) {
         		this.createdNodes.remove(this.createdNodes.size() - 1);
         	}
-        	return false;
+        	return null;
         }
-        
-        PlanNode intermediateParent = NodeEditor.findParent(projectNode, NodeConstants.Types.ACCESS, NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP);
-        if (intermediateParent != null) {
-            intermediateParent.addAsParent(copyNode);
-        } else {
-        	projectNode.getFirstChild().addAsParent(copyNode);
-        }
-		return true;
-    }
+		return copyNode;
+	}
 
 	private Boolean checkConversion(SymbolMap symbolMap,
 			Collection<ElementSymbol> elements, List<WindowFunction> windowFunctions) {

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentCriteriaProcessor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentCriteriaProcessor.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentCriteriaProcessor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -43,6 +43,7 @@
 import org.teiid.query.sql.lang.DependentSetCriteria;
 import org.teiid.query.sql.lang.OrderBy;
 import org.teiid.query.sql.lang.SetCriteria;
+import org.teiid.query.sql.symbol.Array;
 import org.teiid.query.sql.symbol.Constant;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.util.ValueIterator;
@@ -65,6 +66,13 @@
         float maxNdv = NewCalculateCostUtil.UNKNOWN_VALUE;
         
         boolean overMax;
+        
+        long replacementSize() {
+    		return replacement.size() * valueCount;
+    	}
+        
+        long valueCount = 1;
+
     }
 
     class TupleState {
@@ -86,11 +94,17 @@
                 if (!originalVs.isDistinct()) {
 	            	if (sortUtility == null) {
 	            		List<Expression> sortSymbols = new ArrayList<Expression>(dependentSetStates.size());
-		                List<Boolean> sortDirection = new ArrayList<Boolean>(sortSymbols.size());
 		                for (int i = 0; i < dependentSetStates.size(); i++) {
-		                    sortDirection.add(Boolean.valueOf(OrderBy.ASC));
-		                    sortSymbols.add(dependentSetStates.get(i).valueExpression);
+		                    if (dependentSetStates.get(i).valueExpression instanceof Array) {
+		                    	Array array = (Array)dependentSetStates.get(i).valueExpression;
+		                    	for (Expression ex : array.getExpressions()) {
+		                    		sortSymbols.add(ex);
+		                    	}
+		                    } else {
+		                    	sortSymbols.add(dependentSetStates.get(i).valueExpression);
+		                    }
 		                }
+		                List<Boolean> sortDirection = Collections.nCopies(sortSymbols.size(), OrderBy.ASC);
 		                this.sortUtility = new SortUtility(originalVs.getTupleBuffer().createIndexedTupleSource(), sortSymbols, sortDirection, Mode.DUP_REMOVE, dependentNode.getBufferManager(), dependentNode.getConnectionID(), originalVs.getTupleBuffer().getSchema());
 	            	}
 	            	dvs = new DependentValueSource(sortUtility.sort());
@@ -221,6 +235,9 @@
                 SetState state = new SetState();
                 setStates.put(i, state);
                 state.valueExpression = dsc.getValueExpression();
+                if (dsc.hasMultipleAttributes()) {
+                	state.valueCount = ((Array)dsc.getExpression()).getExpressions().size();
+                }
                 TupleState ts = dependentState.get(source);
                 if (ts == null) {
                 	ts = new TupleState(source);
@@ -357,7 +374,7 @@
 		                    }
 		
 		                    isNull |= state.isNull;
-		                    lessThanMax &= state.replacement.size() < maxSize * (run + 1);
+		                    lessThanMax &= state.replacementSize() < maxSize * (run + 1);
 		                }
 		
 		                if (doneCount == source.size()) {
@@ -383,7 +400,7 @@
 	        	}
 	            
 	            for (SetState setState : source) {
-	            	currentPredicates += setState.replacement.size()/maxSize+(setState.replacement.size()%maxSize!=0?1:0);
+	            	currentPredicates += setState.replacementSize()/maxSize+(setState.replacementSize()%maxSize!=0?1:0);
 				}
 	        }
 	        
@@ -417,7 +434,7 @@
     	int numberOfSets = 1;
     	int maxSize = Integer.MAX_VALUE;
     	if (this.maxSetSize > 0) {
-    		maxSize = this.maxSetSize;
+    		maxSize = (int) Math.max(1, this.maxSetSize/state.valueCount);
     		numberOfSets = state.replacement.size()/maxSize + (state.replacement.size()%maxSize!=0?1:0);
     	}
     	Iterator<Object> iter = state.replacement.iterator();

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentProcedureCriteriaProcessor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentProcedureCriteriaProcessor.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentProcedureCriteriaProcessor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -34,6 +34,8 @@
 import org.teiid.query.sql.lang.CompareCriteria;
 import org.teiid.query.sql.lang.Criteria;
 import org.teiid.query.sql.lang.IsNullCriteria;
+import org.teiid.query.sql.symbol.Array;
+import org.teiid.query.sql.symbol.ArrayValue;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.symbol.Reference;
@@ -77,8 +79,8 @@
 
         boolean validRow = true;
 
-        for (Iterator i = Criteria.separateCriteriaByAnd(critInProgress).iterator(); i.hasNext();) {
-            Criteria crit = (Criteria)i.next();
+        for (Iterator<Criteria> i = Criteria.separateCriteriaByAnd(critInProgress).iterator(); i.hasNext() && validRow;) {
+            Criteria crit = i.next();
 
             Object value = null;
             boolean nullAllowed = false;
@@ -90,31 +92,30 @@
             } else if (crit instanceof CompareCriteria) {
                 CompareCriteria compare = (CompareCriteria)crit;
                 value = compare.getRightExpression();
+                if (compare.getLeftExpression() instanceof Array) {
+                	Array array = (Array)compare.getLeftExpression();
+                	if (value instanceof Expression) {
+            		    value = eval.evaluate((Expression)value, null);
+            		}
+                	if (value == null) {
+                		validRow = false;
+                		break;
+                	}
+                	ArrayValue valueArray = (ArrayValue)value;
+                	for (int j = 0; j < array.getExpressions().size(); j++) {
+                		validRow = setParam(context, valueArray.getValues()[j], nullAllowed, (Reference) array.getExpressions().get(j));
+                		if (!validRow) {
+                			break;
+                		}
+                	}
+                	continue;
+                }
                 parameter = (Reference)compare.getLeftExpression();
             } else {
                 Assertion.failed("Unknown predicate type"); //$NON-NLS-1$
             }
 
-            if (value instanceof Expression) {
-                value = eval.evaluate((Expression)value, null);
-            }
-
-            if (value == null && !nullAllowed) {
-                validRow = false;
-                break;
-            }
-
-            ElementSymbol parameterSymbol = parameter.getExpression();
-            if (context.containsVariable(parameterSymbol)) {
-	            Object existingValue = context.getValue(parameterSymbol);
-	
-	            if ((value != null && !value.equals(existingValue)) || (value == null && existingValue != null)) {
-	                validRow = false;
-	                break;
-	            }
-            }
-
-            context.setValue(parameterSymbol, value);
+            validRow = setParam(context, value, nullAllowed, parameter);
         }
 
         critInProgress = null;
@@ -136,5 +137,30 @@
 
         return true;
     }
+
+	private boolean setParam(VariableContext context,
+			Object value, boolean nullAllowed, Reference parameter)
+			throws ExpressionEvaluationException, BlockedException,
+			TeiidComponentException {
+		if (value instanceof Expression) {
+		    value = eval.evaluate((Expression)value, null);
+		}
+
+		if (value == null && !nullAllowed) {
+		    return false;
+		}
+
+		ElementSymbol parameterSymbol = parameter.getExpression();
+		if (context.containsVariable(parameterSymbol)) {
+		    Object existingValue = context.getValue(parameterSymbol);
+
+		    if ((value != null && !value.equals(existingValue)) || (value == null && existingValue != null)) {
+		        return false;
+		    }
+		}
+
+		context.setValue(parameterSymbol, value);
+		return true;
+	}
     
 }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -35,9 +35,10 @@
 import org.teiid.core.TeiidProcessingException;
 import org.teiid.core.types.DataTypeManager;
 import org.teiid.core.util.Assertion;
+import org.teiid.query.sql.symbol.Array;
+import org.teiid.query.sql.symbol.ArrayValue;
 import org.teiid.query.sql.symbol.Constant;
 import org.teiid.query.sql.symbol.Expression;
-import org.teiid.query.sql.util.ValueIterator;
 import org.teiid.query.sql.util.ValueIteratorSource;
 
 
@@ -70,15 +71,42 @@
      * @throws TeiidComponentException 
      * @see org.teiid.query.sql.util.ValueIteratorSource#getValueIterator(org.teiid.query.sql.symbol.Expression)
      */
-    public ValueIterator getValueIterator(Expression valueExpression) throws  TeiidComponentException {
+    public TupleSourceValueIterator getValueIterator(Expression valueExpression) throws  TeiidComponentException {
     	IndexedTupleSource its = buffer.createIndexedTupleSource();
     	int index = 0;
     	if (valueExpression != null) {
-    		index = schema.indexOf(valueExpression);
-    		Assertion.assertTrue(index != -1);
+    		if (valueExpression instanceof Array) {
+    			Array array = (Array)valueExpression;
+    			List<Expression> exprs = array.getExpressions();
+    			final int[] indexes = new int[exprs.size()];
+    			for (int i = 0; i < exprs.size(); i++) {
+					indexes[i] = getIndex(exprs.get(i));
+				}
+    	        return new TupleSourceValueIterator(its, index) {
+    	        	@Override
+    	        	public Object next() throws TeiidComponentException {
+    	        		List<?> tuple = super.nextTuple();
+    	        		Object[] a = new Object[indexes.length];
+    	        		for (int i = 0; i < indexes.length; i++) {
+    	        			a[i] = tuple.get(indexes[i]);
+    	        			if (a[i] == null) {
+    	        				return null; //TODO: this is a hack
+    	        			}
+    	        		}
+    	        		return new ArrayValue(a);
+    	        	}
+    	        };
+    		} 
+    		index = getIndex(valueExpression);
     	}
         return new TupleSourceValueIterator(its, index);
     }
+
+	private int getIndex(Expression valueExpression) {
+		int index = schema.indexOf(valueExpression);
+		Assertion.assertTrue(index != -1);
+		return index;
+	}
     
     public Set<Object> getCachedSet(Expression valueExpression) throws TeiidComponentException, TeiidProcessingException {
     	Set<Object> result = null;
@@ -89,25 +117,31 @@
 			if (buffer.getRowCount() > buffer.getBatchSize()) {
 				return null;
 			}
-			IndexedTupleSource its = buffer.createIndexedTupleSource();
+			TupleSourceValueIterator ve = getValueIterator(valueExpression);
         	int index = 0;
-        	if (valueExpression != null) {
-        		index = schema.indexOf(valueExpression);
+        	Class<?> type = null;
+        	if (valueExpression instanceof Array) {
+        		type = ((Array)valueExpression).getBaseType();
+        	} else { 	
+        		if (valueExpression != null) {
+	        		index = schema.indexOf(valueExpression);
+	            	Assertion.assertTrue(index != -1);
+        		}
+            	type = ((Expression)schema.get(index)).getType();
         	}
-        	Assertion.assertTrue(index != -1);
-        	Class<?> type = ((Expression)schema.get(index)).getType();
+
         	if (!DataTypeManager.isHashable(type)) {
         		result = new TreeSet<Object>(Constant.COMPARATOR);
     		} else {
     			result = new HashSet<Object>();
     		}
-        	while (its.hasNext()) {
-        		Object value = its.nextTuple().get(index);
+        	while (ve.hasNext()) {
+        		Object value = ve.next();
         		if (value != null) {
         			result.add(value);
         		}
         	}
-        	its.closeSource();
+        	ve.close();
         	if (cachedSets == null) {
         		cachedSets = new HashMap<Expression, Set<Object>>();
         	}

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/TupleSourceValueIterator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/TupleSourceValueIterator.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/TupleSourceValueIterator.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -22,10 +22,11 @@
 
 package org.teiid.query.processor.relational;
 
+import java.util.List;
+
 import org.teiid.common.buffer.IndexedTupleSource;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
-import org.teiid.query.QueryPlugin;
 import org.teiid.query.sql.util.ValueIterator;
 
 
@@ -63,12 +64,20 @@
 	 * @see java.util.Iterator#next()
 	 */
 	public Object next() throws TeiidComponentException{
-	    try {
-            return tupleSourceIterator.nextTuple().get(columnIndex);
+	    return nextTuple().get(columnIndex);
+	}
+
+	protected List<?> nextTuple() throws TeiidComponentException {
+		try {
+            return tupleSourceIterator.nextTuple();
         } catch (TeiidProcessingException e) {
              throw new TeiidComponentException(e);
         }
 	}
+	
+	public void close() {
+		this.tupleSourceIterator.closeSource();
+	}
     
 	/**
 	 * Flags a reset as being needed

Modified: trunk/engine/src/main/java/org/teiid/query/sql/LanguageVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/LanguageVisitor.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/LanguageVisitor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -22,85 +22,9 @@
 
 package org.teiid.query.sql;
 
-import org.teiid.query.sql.lang.AlterProcedure;
-import org.teiid.query.sql.lang.AlterTrigger;
-import org.teiid.query.sql.lang.AlterView;
-import org.teiid.query.sql.lang.ArrayTable;
-import org.teiid.query.sql.lang.BatchedUpdateCommand;
-import org.teiid.query.sql.lang.BetweenCriteria;
-import org.teiid.query.sql.lang.CompareCriteria;
-import org.teiid.query.sql.lang.CompoundCriteria;
-import org.teiid.query.sql.lang.Create;
-import org.teiid.query.sql.lang.Delete;
-import org.teiid.query.sql.lang.DependentSetCriteria;
-import org.teiid.query.sql.lang.Drop;
-import org.teiid.query.sql.lang.DynamicCommand;
-import org.teiid.query.sql.lang.ExistsCriteria;
-import org.teiid.query.sql.lang.ExpressionCriteria;
-import org.teiid.query.sql.lang.From;
-import org.teiid.query.sql.lang.GroupBy;
-import org.teiid.query.sql.lang.Insert;
-import org.teiid.query.sql.lang.Into;
-import org.teiid.query.sql.lang.IsNullCriteria;
-import org.teiid.query.sql.lang.JoinPredicate;
-import org.teiid.query.sql.lang.JoinType;
-import org.teiid.query.sql.lang.Limit;
-import org.teiid.query.sql.lang.MatchCriteria;
-import org.teiid.query.sql.lang.NotCriteria;
-import org.teiid.query.sql.lang.Option;
-import org.teiid.query.sql.lang.OrderBy;
-import org.teiid.query.sql.lang.OrderByItem;
-import org.teiid.query.sql.lang.ProcedureContainer;
-import org.teiid.query.sql.lang.Query;
-import org.teiid.query.sql.lang.Select;
-import org.teiid.query.sql.lang.SetClause;
-import org.teiid.query.sql.lang.SetClauseList;
-import org.teiid.query.sql.lang.SetCriteria;
-import org.teiid.query.sql.lang.SetQuery;
-import org.teiid.query.sql.lang.StoredProcedure;
-import org.teiid.query.sql.lang.SubqueryCompareCriteria;
-import org.teiid.query.sql.lang.SubqueryFromClause;
-import org.teiid.query.sql.lang.SubquerySetCriteria;
-import org.teiid.query.sql.lang.TextTable;
-import org.teiid.query.sql.lang.UnaryFromClause;
-import org.teiid.query.sql.lang.Update;
-import org.teiid.query.sql.lang.WithQueryCommand;
-import org.teiid.query.sql.lang.XMLTable;
-import org.teiid.query.sql.proc.AssignmentStatement;
-import org.teiid.query.sql.proc.Block;
-import org.teiid.query.sql.proc.BranchingStatement;
-import org.teiid.query.sql.proc.CommandStatement;
-import org.teiid.query.sql.proc.CreateProcedureCommand;
-import org.teiid.query.sql.proc.DeclareStatement;
-import org.teiid.query.sql.proc.IfStatement;
-import org.teiid.query.sql.proc.LoopStatement;
-import org.teiid.query.sql.proc.RaiseErrorStatement;
-import org.teiid.query.sql.proc.TriggerAction;
-import org.teiid.query.sql.proc.WhileStatement;
-import org.teiid.query.sql.symbol.AggregateSymbol;
-import org.teiid.query.sql.symbol.AliasSymbol;
-import org.teiid.query.sql.symbol.CaseExpression;
-import org.teiid.query.sql.symbol.Constant;
-import org.teiid.query.sql.symbol.DerivedColumn;
-import org.teiid.query.sql.symbol.ElementSymbol;
-import org.teiid.query.sql.symbol.ExpressionSymbol;
-import org.teiid.query.sql.symbol.Function;
-import org.teiid.query.sql.symbol.GroupSymbol;
-import org.teiid.query.sql.symbol.MultipleElementSymbol;
-import org.teiid.query.sql.symbol.QueryString;
-import org.teiid.query.sql.symbol.Reference;
-import org.teiid.query.sql.symbol.ScalarSubquery;
-import org.teiid.query.sql.symbol.SearchedCaseExpression;
-import org.teiid.query.sql.symbol.TextLine;
-import org.teiid.query.sql.symbol.WindowFunction;
-import org.teiid.query.sql.symbol.WindowSpecification;
-import org.teiid.query.sql.symbol.XMLAttributes;
-import org.teiid.query.sql.symbol.XMLElement;
-import org.teiid.query.sql.symbol.XMLForest;
-import org.teiid.query.sql.symbol.XMLNamespaces;
-import org.teiid.query.sql.symbol.XMLParse;
-import org.teiid.query.sql.symbol.XMLQuery;
-import org.teiid.query.sql.symbol.XMLSerialize;
+import org.teiid.query.sql.lang.*;
+import org.teiid.query.sql.proc.*;
+import org.teiid.query.sql.symbol.*;
 
 /**
  * <p>The LanguageVisitor can be used to visit a LanguageObject as if it were a tree
@@ -218,4 +142,6 @@
 
 	public void visit(WindowFunction windowFunction) {}
 	public void visit(WindowSpecification windowSpecification) {}
+
+	public void visit(Array array) {}
 }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -22,11 +22,16 @@
 
 package org.teiid.query.sql.lang;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.core.util.HashCodeUtil;
 import org.teiid.query.optimizer.relational.rules.NewCalculateCostUtil;
 import org.teiid.query.processor.relational.DependentValueSource;
 import org.teiid.query.sql.LanguageVisitor;
+import org.teiid.query.sql.symbol.Array;
 import org.teiid.query.sql.symbol.ContextReference;
 import org.teiid.query.sql.symbol.Expression;
 
@@ -40,6 +45,13 @@
  */
 public class DependentSetCriteria extends AbstractSetCriteria implements ContextReference {
 	
+	public static class AttributeComparison {
+		public Expression dep; 
+		public Expression ind;
+		public float ndv;
+		public float maxNdv;
+	}
+	
     /**
      * Specifies the expression whose values we want to return in the iterator
      */
@@ -51,6 +63,9 @@
     private float ndv = NewCalculateCostUtil.UNKNOWN_VALUE;
     private float maxNdv = NewCalculateCostUtil.UNKNOWN_VALUE;
     
+    private float[] ndvs;
+    private float[] maxNdvs;
+    
     /**
      * set only for dependent pushdown
      */
@@ -62,9 +77,47 @@
     public DependentSetCriteria(Expression expr, String id) {
         setExpression(expr);
         this.id = id;
-    }    
+    }  
+    
+    public void setAttributes(List<AttributeComparison> attributes) {
+		this.ndvs = new float[attributes.size()];
+		this.maxNdvs = new float[attributes.size()];
+		for (int i = 0; i < attributes.size(); i++) {
+			AttributeComparison comp = attributes.get(i);
+			this.ndvs[i] = comp.ndv;
+			this.maxNdvs[i] = comp.maxNdv;
+		}
+	}
+    
+    /**
+     * There is a mismatch between the expression form and the more convenient attribute comparison,
+     * so we reconstruct when needed
+     */
+    public List<AttributeComparison> getAttributes() {
+		if (!hasMultipleAttributes()) {
+			AttributeComparison comp = new AttributeComparison();
+			comp.dep = getExpression();
+			comp.ind = getValueExpression();
+			comp.ndv = ndv;
+			comp.maxNdv = maxNdv;
+			return Arrays.asList(comp);
+		}
+		ArrayList<AttributeComparison> result = new ArrayList<AttributeComparison>();
+		for (int i = 0; i < ndvs.length; i++) {
+			AttributeComparison comp = new AttributeComparison();
+			comp.dep = ((Array)getExpression()).getExpressions().get(i);
+			comp.ind = ((Array)getValueExpression()).getExpressions().get(i);
+			comp.ndv = ndv;
+			comp.maxNdv = maxNdv;
+			result.add(comp);
+		}
+		return result;
+	}
+    
+    public boolean hasMultipleAttributes() {
+    	return this.ndvs != null && this.ndvs.length > 1;
+    }
         
-    @Override
     public String getContextSymbol() {
     	return id;
     }
@@ -161,6 +214,8 @@
         criteriaCopy.id = this.id;
         criteriaCopy.ndv = this.ndv;
         criteriaCopy.maxNdv = this.maxNdv;
+        criteriaCopy.maxNdvs = this.maxNdvs;
+        criteriaCopy.ndvs = this.ndvs;
         return criteriaCopy;
     }
     

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -29,7 +29,6 @@
 import org.teiid.query.sql.LanguageVisitor;
 import org.teiid.query.sql.lang.PredicateCriteria.Negatable;
 import org.teiid.query.sql.symbol.ContextReference;
-import org.teiid.query.sql.symbol.Expression;
 
 
 /**
@@ -130,11 +129,6 @@
     	return id;
     }
     
-    @Override
-    public Expression getValueExpression() {
-    	return null;
-    }
-
     public QueryCommand getCommand() {
         return this.command;
     }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/SubqueryCompareCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/SubqueryCompareCriteria.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/SubqueryCompareCriteria.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -90,11 +90,6 @@
     	return id;
     }
     
-    @Override
-    public Expression getValueExpression() {
-    	return null;
-    }
-
     /**
      * Get the predicate quantifier - returns one of the following:
      * <ul><li>{@link #NO_QUANTIFIER}</li>

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -70,11 +70,6 @@
     	return id;
     }
     
-    @Override
-    public Expression getValueExpression() {
-    	return null;
-    }
-
     /**
      * Set the subquery command (either a SELECT or a procedure execution).
      * @param command Command to execute to get the values for the criteria

Modified: trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -617,6 +617,13 @@
         postVisitVisitor(obj);
     }
     
+    @Override
+    public void visit(Array array) {
+    	preVisitVisitor(array);
+    	visitNodes(array.getExpressions());
+    	postVisitVisitor(array);
+    }
+    
     public static void doVisit(LanguageObject object, LanguageVisitor visitor, boolean order) {
     	doVisit(object, visitor, order, false);
     }

Added: trunk/engine/src/main/java/org/teiid/query/sql/symbol/Array.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/Array.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/Array.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -0,0 +1,93 @@
+/*
+ * 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 org.teiid.query.sql.symbol;
+
+import java.util.List;
+
+import org.teiid.core.types.DataTypeManager;
+import org.teiid.core.util.EquivalenceUtil;
+import org.teiid.core.util.HashCodeUtil;
+import org.teiid.query.sql.LanguageObject;
+import org.teiid.query.sql.LanguageVisitor;
+import org.teiid.query.sql.visitor.SQLStringVisitor;
+
+public class Array implements Expression {
+
+	private Class<?> baseType;
+	private List<Expression> expressions;
+	
+	public Array(Class<?> baseType, List<Expression> expresssions) {
+		this.baseType = baseType;
+		this.expressions = expresssions;
+	}
+	
+	@Override
+	public Class<?> getType() {
+		return DataTypeManager.DefaultDataClasses.OBJECT;
+	}
+
+	@Override
+	public void acceptVisitor(LanguageVisitor visitor) {
+		visitor.visit(this);
+	}
+	
+	@Override
+	public Array clone() {
+		return new Array(baseType, LanguageObject.Util.deepClone(getExpressions(), Expression.class));
+	}
+	
+	public Class<?> getBaseType() {
+		return baseType;
+	}
+	
+	public void setBaseType(Class<?> baseType) {
+		this.baseType = baseType;
+	}
+	
+	public List<Expression> getExpressions() {
+		return expressions;
+	}
+	
+	@Override
+	public int hashCode() {
+		return HashCodeUtil.hashCode(0, getExpressions());
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj) {
+			return true;
+		}
+	    if (!(obj instanceof Array)) {
+	    	return false;
+	    }
+		Array other = (Array) obj;
+		return EquivalenceUtil.areEqual(baseType, other.baseType) && EquivalenceUtil.areEqual(expressions, other.expressions);
+	}
+	
+	@Override
+	public String toString() {
+		return SQLStringVisitor.getSQLString(this);
+	}
+	
+}


Property changes on: trunk/engine/src/main/java/org/teiid/query/sql/symbol/Array.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/engine/src/main/java/org/teiid/query/sql/symbol/ArrayValue.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/ArrayValue.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/ArrayValue.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -0,0 +1,79 @@
+/*
+ * 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 org.teiid.query.sql.symbol;
+
+import java.util.Arrays;
+
+public class ArrayValue implements Comparable<ArrayValue> {
+	private Object[] values;
+	
+	public ArrayValue(Object[] values) {
+		this.values = values;
+	}
+
+	@Override
+	public int compareTo(ArrayValue o) {
+		int len1 = values.length;
+		int len2 = o.values.length;
+	    int lim = Math.min(len1, len2);
+	    for (int k = 0; k < lim; k++) {
+	    	Object object1 = values[k];
+			Object object2 = o.values[k];
+			if (object1 == null) {
+	    		if (object2 != null) {
+	    			return -1;
+	    		}
+	    		continue;
+	    	} else if (object2 == null) {
+	    		return 1;
+	    	}
+			int comp = Constant.COMPARATOR.compare(object1, object2);
+			if (comp != 0) {
+			    return comp;
+			}
+	    }
+	    return len1 - len2;
+	}
+	
+	@Override
+	public int hashCode() {
+		return Arrays.hashCode(values);
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (!(obj instanceof ArrayValue)) {
+			return false;
+		}
+		ArrayValue other = (ArrayValue)obj;
+		return Arrays.equals(values, other.values);
+	}
+	
+	public Object[] getValues() {
+		return values;
+	}
+	
+}


Property changes on: trunk/engine/src/main/java/org/teiid/query/sql/symbol/ArrayValue.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/ContextReference.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/ContextReference.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/ContextReference.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -26,6 +26,4 @@
 
 	public String getContextSymbol();
 	
-	public Expression getValueExpression();
-	
 }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/Reference.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/Reference.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/Reference.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -92,11 +92,6 @@
     	return "$param/pos" + this.refIndex; //$NON-NLS-1$
     }
     
-    @Override
-    public Expression getValueExpression() {
-    	return this.expression;
-    }
-
     public ElementSymbol getExpression() {
         return this.expression;    
     }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/ScalarSubquery.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/ScalarSubquery.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/ScalarSubquery.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -72,11 +72,6 @@
     	return id;
     }
     
-    @Override
-    public Expression getValueExpression() {
-    	return null;
-    }
-
     /**
      * @see org.teiid.query.sql.symbol.Expression#getType()
      */

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	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -426,4 +426,12 @@
     	}
     }
     
+    @Override
+    public void visit(Array array) {
+    	List<Expression> exprs = array.getExpressions();
+		for (int i = 0; i < exprs.size(); i++) {
+    		exprs.set(i, replaceExpression(exprs.get(i)));
+    	}
+    }
+    
 }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -2041,6 +2041,13 @@
     	}
     	append(Tokens.RPAREN);	
     }
+    
+    @Override
+    public void visit(Array array) {
+    	append(Tokens.LPAREN);
+    	registerNodes(array.getExpressions(), 0);
+    	append(Tokens.RPAREN);
+    }
 
     public static String escapeSinglePart( String part ) {
         if (isReservedWord(part)) {

Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2012-08-10 14:52:39 UTC (rev 4307)
@@ -1874,7 +1874,7 @@
 /*
 name=select clause
 description=The columns returned by a query.  Can optionally be distinct.
-example={code:sql}SELECT *{code}\n{code:sql}"SELECT DISTINCT a, b, c{code}
+example={code:sql}SELECT *{code}\n{code:sql}SELECT DISTINCT a, b, c{code}
  */
 Select select(ParseInfo info) :
 {

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestDependentJoins.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestDependentJoins.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestDependentJoins.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -744,6 +744,7 @@
         caps.setCapabilitySupport(Capability.QUERY_SEARCHED_CASE, true);
         caps.setCapabilitySupport(Capability.QUERY_FROM_JOIN_INNER, true);
         caps.setCapabilitySupport(Capability.QUERY_FROM_GROUP_ALIAS, true);
+        caps.setCapabilitySupport(Capability.ARRAY_TYPE, true);
         caps.setSourceProperty(Capability.MAX_IN_CRITERIA_SIZE, new Integer(1000));
         caps.setFunctionSupport("||", true); //$NON-NLS-1$
         capFinder.addCapabilities("BQT1", caps); //$NON-NLS-1$
@@ -757,7 +758,7 @@
             "SELECT table1comp.IntKey, table1comp.key1, BQT1.SmallA.StringKey FROM (SELECT t1.*, (STRINGKEY || STRINGNUM) AS key1 FROM BQT2.SmallA AS t1) AS table1comp, BQT1.SmallA WHERE table1comp.key1 = BQT1.SmallA.StringKey AND table1comp.key1 = BQT1.SmallA.StringNum",  //$NON-NLS-1$
             metadata,
             null, capFinder,
-            new String[] {"SELECT g_0.StringKey, g_0.StringNum, g_0.IntKey FROM BQT2.SmallA AS g_0", "SELECT g_0.StringKey, g_0.StringNum FROM BQT1.SmallA AS g_0 WHERE (g_0.StringNum = g_0.StringKey) AND (g_0.StringKey IN (<dependent values>)) AND (g_0.StringNum IN (<dependent values>))"}, //$NON-NLS-1$ //$NON-NLS-2$
+            new String[] {"SELECT g_0.StringKey, g_0.StringNum, g_0.IntKey FROM BQT2.SmallA AS g_0", "SELECT g_0.StringKey, g_0.StringNum FROM BQT1.SmallA AS g_0 WHERE (g_0.StringNum = g_0.StringKey) AND ((g_0.StringKey, g_0.StringNum) IN (<dependent values>))"}, //$NON-NLS-1$ //$NON-NLS-2$
             TestOptimizer.ComparisonMode.EXACT_COMMAND_STRING );
 
         TestOptimizer.checkNodeTypes(plan, new int[] {

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestDependentJoins.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestDependentJoins.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestDependentJoins.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -163,7 +163,33 @@
        // Run query
        TestProcessor.helpProcess(plan, dataManager, expected);
    }
+    
+    @Test public void testMultiCritDepJoin2a() { 
+        // Create query 
+        String sql = "SELECT pm1.g1.e1 FROM pm1.g1, pm2.g1 WHERE pm2.g1.e1=pm1.g1.e1 AND pm1.g1.e2=pm2.g1.e2 order by pm1.g1.e1 option makedep pm1.g1"; //$NON-NLS-1$
+        
+        // Create expected results
+        List[] expected = new List[] { 
+            Arrays.asList(new Object[] { "a" }), //$NON-NLS-1$
+            Arrays.asList(new Object[] { "a" }), //$NON-NLS-1$
+            Arrays.asList(new Object[] { "a" }), //$NON-NLS-1$
+            Arrays.asList(new Object[] { "a" }), //$NON-NLS-1$
+            Arrays.asList(new Object[] { "a" }), //$NON-NLS-1$
+            Arrays.asList(new Object[] { "b" }), //$NON-NLS-1$
+            Arrays.asList(new Object[] { "c" }) //$NON-NLS-1$
+        };    
+        
+        // Construct data manager with data
+        FakeDataManager dataManager = new FakeDataManager();
+        TestProcessor.sampleData1(dataManager);
+        BasicSourceCapabilities bsc = TestOptimizer.getTypicalCapabilities();
+        bsc.setCapabilitySupport(Capability.ARRAY_TYPE, true);
+        ProcessorPlan plan = helpGetPlan(sql);
 
+        // Run query
+        TestProcessor.helpProcess(plan, dataManager, expected);
+    }
+
     /** SELECT pm1.g1.e1 FROM pm1.g1, pm2.g1 WHERE pm2.g1.e1=pm1.g1.e1 AND pm1.g1.e2=pm2.g1.e2 */
     @Test public void testMultiCritDepJoin3() { 
        // Create query 
@@ -1034,7 +1060,12 @@
     }
     
     @Test public void testMakeIndHintPushdown() { 
-        // Create query 
+    	helpTestPushdown(true);
+    	helpTestPushdown(false);
+    }
+
+	private void helpTestPushdown(boolean supportsArrayType) {
+		// Create query 
         String sql = "SELECT pm1.g1.e1 FROM /*+ MAKEIND */ pm1.g1, pm2.g1 WHERE pm1.g1.e1 = pm2.g1.e1 AND pm1.g1.e2=pm2.g1.e2 order by pm1.g1.e1"; //$NON-NLS-1$
         
         // Create expected results
@@ -1045,9 +1076,14 @@
         // Construct data manager with data
         HardcodedDataManager dataManager = new HardcodedDataManager(RealMetadataFactory.example1Cached());
         dataManager.addData("SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM g1 AS g_0 ORDER BY c_0, c_1", new List[] {Arrays.asList("a", 1)});
-        dataManager.addData("SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM g1 AS g_0 WHERE g_0.e1 = ? AND g_0.e2 = ? ORDER BY c_0, c_1", new List[] {Arrays.asList("a", 1)});
+        if (supportsArrayType) {
+        	dataManager.addData("SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM g1 AS g_0 WHERE (g_0.e1, g_0.e2) = ? ORDER BY c_0, c_1", new List[] {Arrays.asList("a", 1)});
+        } else {
+        	dataManager.addData("SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM g1 AS g_0 WHERE g_0.e1 = ? AND g_0.e2 = ? ORDER BY c_0, c_1", new List[] {Arrays.asList("a", 1)});
+        }
         BasicSourceCapabilities bsc = TestOptimizer.getTypicalCapabilities();
         bsc.setCapabilitySupport(Capability.DEPENDENT_JOIN, true);
+        bsc.setCapabilitySupport(Capability.ARRAY_TYPE, supportsArrayType);
         DefaultCapabilitiesFinder dcf = new DefaultCapabilitiesFinder(bsc);
         // Plan query
         ProcessorPlan plan = TestProcessor.helpGetPlan(sql, RealMetadataFactory.example1Cached(), dcf);
@@ -1060,6 +1096,6 @@
         assertEquals(1, s.getDependentValues().size());
         List<? extends List<?>> vals = s.getDependentValues().values().iterator().next();
         assertEquals(1, vals.size());
-    }
+	}
     
 }

Added: trunk/engine/src/test/java/org/teiid/query/sql/symbol/TestArray.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/sql/symbol/TestArray.java	                        (rev 0)
+++ trunk/engine/src/test/java/org/teiid/query/sql/symbol/TestArray.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -0,0 +1,55 @@
+/*
+ * 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 org.teiid.query.sql.symbol;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.teiid.core.types.DataTypeManager;
+import org.teiid.core.util.UnitTestUtil;
+
+ at SuppressWarnings("nls")
+public class TestArray {
+
+	@Test public void testArrayValueCompare() {
+		ArrayValue a1 = new ArrayValue(new Object[] {1, 2, 3});
+		
+		UnitTestUtil.helpTestEquivalence(0, a1, a1);
+		
+		ArrayValue a2 = new ArrayValue(new Object[] {1, 2});
+		
+		UnitTestUtil.helpTestEquivalence(1, a1, a2);
+	}
+	
+	@Test public void testArrayClone() {
+		Array array = new Array(DataTypeManager.DefaultDataClasses.OBJECT, Arrays.asList((Expression)new ElementSymbol("e1")));
+		
+		Array a1 = array.clone();
+		
+		assertNotSame(a1, array);
+		assertNotSame(a1.getExpressions().get(0), array.getExpressions().get(0));
+	}
+	
+}


Property changes on: trunk/engine/src/test/java/org/teiid/query/sql/symbol/TestArray.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestExpressionMappingVisitor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestExpressionMappingVisitor.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestExpressionMappingVisitor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -31,27 +31,20 @@
 import java.util.Map;
 
 import org.junit.Test;
+import org.teiid.core.types.DataTypeManager;
 import org.teiid.language.SQLConstants.NonReserved;
 import org.teiid.query.sql.LanguageObject;
 import org.teiid.query.sql.lang.CompareCriteria;
 import org.teiid.query.sql.lang.Select;
 import org.teiid.query.sql.lang.SetCriteria;
-import org.teiid.query.sql.symbol.AggregateSymbol;
-import org.teiid.query.sql.symbol.CaseExpression;
-import org.teiid.query.sql.symbol.Constant;
-import org.teiid.query.sql.symbol.ElementSymbol;
-import org.teiid.query.sql.symbol.Expression;
-import org.teiid.query.sql.symbol.Function;
-import org.teiid.query.sql.symbol.SearchedCaseExpression;
-import org.teiid.query.sql.symbol.TestCaseExpression;
-import org.teiid.query.sql.symbol.TestSearchedCaseExpression;
+import org.teiid.query.sql.symbol.*;
 import org.teiid.translator.SourceSystemFunctions;
 
 
-
+ at SuppressWarnings("nls")
 public class TestExpressionMappingVisitor {
 
-    public void helpTest(LanguageObject original, Map map, LanguageObject expected) {
+    public void helpTest(LanguageObject original, Map<Expression, Expression> map, LanguageObject expected) {
         ExpressionMappingVisitor.mapExpressions(original, map);
         
         assertEquals("Did not get expected mapped expression", expected, original);     //$NON-NLS-1$
@@ -60,7 +53,7 @@
     @Test public void testCompareCriteria1() {
         ElementSymbol e1 = new ElementSymbol("e1"); //$NON-NLS-1$
         Function f = new Function("+", new Expression[] { new Constant(new Integer(2)), new Constant(new Integer(5)) }); //$NON-NLS-1$
-        Map map = new HashMap();
+        Map<Expression, Expression> map = new HashMap<Expression, Expression>();
         map.put(e1, f);
         CompareCriteria before = new CompareCriteria(e1, CompareCriteria.EQ, new Constant("xyz")); //$NON-NLS-1$
         CompareCriteria after = new CompareCriteria(f, CompareCriteria.EQ, new Constant("xyz")); //$NON-NLS-1$
@@ -70,7 +63,7 @@
     @Test public void testCompareCriteria2() {
         ElementSymbol e1 = new ElementSymbol("e1"); //$NON-NLS-1$
         Function f = new Function("+", new Expression[] { new Constant(new Integer(2)), new Constant(new Integer(5)) }); //$NON-NLS-1$
-        Map map = new HashMap();
+        Map<Expression, Expression> map = new HashMap<Expression, Expression>();
         map.put(e1, f);
         CompareCriteria before = new CompareCriteria(new Constant("xyz"), CompareCriteria.EQ, e1); //$NON-NLS-1$
         CompareCriteria after = new CompareCriteria(new Constant("xyz"), CompareCriteria.EQ, f); //$NON-NLS-1$
@@ -91,7 +84,7 @@
         ElementSymbol e7 = new ElementSymbol("e7"); //$NON-NLS-1$
         Function f4 = new Function("*", new Expression[] { e5, e6 }); //$NON-NLS-1$
                         
-        Map map = new HashMap();
+        Map<Expression, Expression> map = new HashMap<Expression, Expression>();
         map.put(e3, f4);
         map.put(e2, e7);
         
@@ -107,14 +100,14 @@
         Constant c1 = new Constant("xyz"); //$NON-NLS-1$
         Constant c2 = new Constant("abc"); //$NON-NLS-1$
         Constant c3 = new Constant("def"); //$NON-NLS-1$
-        List values = new ArrayList();
+        List<Expression> values = new ArrayList<Expression>();
         values.add(c1);
         values.add(c2);
-        List mappedValues = new ArrayList();
+        List<Expression> mappedValues = new ArrayList<Expression>();
         mappedValues.add(c1);
         mappedValues.add(c3);
         
-        Map map = new HashMap();
+        Map<Expression, Expression> map = new HashMap<Expression, Expression>();
         map.put(e1, e2);
         map.put(c2, c3);
         
@@ -129,11 +122,11 @@
         Constant a = new Constant(String.valueOf('a'));
         Constant z = new Constant(String.valueOf('z'));
         
-        HashMap map = new HashMap();
+        HashMap<Expression, Expression> map = new HashMap<Expression, Expression>();
         map.put(x, y);
         map.put(a, z);
         
-        ArrayList whens = new ArrayList(), thens = new ArrayList();
+        ArrayList<Expression> whens = new ArrayList<Expression>(), thens = new ArrayList<Expression>();
         whens.add(new Constant(String.valueOf('z')));
         thens.add(new Constant(new Integer(0)));
         whens.add(new Constant(String.valueOf('b')));
@@ -150,10 +143,10 @@
         ElementSymbol x = new ElementSymbol("x"); //$NON-NLS-1$
         ElementSymbol y = new ElementSymbol("y"); //$NON-NLS-1$
         
-        HashMap map = new HashMap();
+        HashMap<Expression, Expression> map = new HashMap<Expression, Expression>();
         map.put(x, y);
         
-        ArrayList whens = new ArrayList(), thens = new ArrayList();
+        ArrayList<Expression> whens = new ArrayList<Expression>(), thens = new ArrayList<Expression>();
         whens.add(new CompareCriteria(y, CompareCriteria.EQ, new Constant(new Integer(0))));
         thens.add(new Constant(new Integer(0)));
         whens.add(new CompareCriteria(y, CompareCriteria.EQ, new Constant(new Integer(1))));
@@ -170,7 +163,7 @@
         ElementSymbol x = new ElementSymbol("y.x"); //$NON-NLS-1$
         ElementSymbol y = new ElementSymbol("z.X"); //$NON-NLS-1$
         
-        HashMap map = new HashMap();
+        HashMap<Expression, Expression> map = new HashMap<Expression, Expression>();
         map.put(x, y);
         
         LanguageObject toMap = new Select(Arrays.asList(x));
@@ -215,4 +208,14 @@
         assertEquals("(SUM(SUM(g1.e1)) + SUM(SUM(g1.e1)))", f.toString()); //$NON-NLS-1$
     }
     
+    @Test public void testArray() {
+    	Expression e1 = new ElementSymbol("g1.e1"); //$NON-NLS-1$
+    	Expression e2 = new ElementSymbol("g1.e2"); //$NON-NLS-1$
+    	Map<Expression, ElementSymbol> map = new HashMap<Expression, ElementSymbol>();
+    	map.put(e1, new ElementSymbol("foo"));
+    	Array a = new Array(DataTypeManager.DefaultDataClasses.OBJECT, Arrays.asList(e1, e2));
+    	ExpressionMappingVisitor.mapExpressions(a, map);
+        assertEquals("(foo, g1.e2)", a.toString()); //$NON-NLS-1$
+    }
+    
 }

Modified: trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java	2012-08-07 23:34:56 UTC (rev 4306)
+++ trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java	2012-08-10 14:52:39 UTC (rev 4307)
@@ -47,6 +47,7 @@
 import org.teiid.query.sql.proc.RaiseErrorStatement;
 import org.teiid.query.sql.symbol.*;
 import org.teiid.query.unittest.RealMetadataFactory;
+import org.teiid.translator.TypeFacility;
 
 @SuppressWarnings("nls")
 public class TestSQLStringVisitor {
@@ -1696,5 +1697,10 @@
     	String sql = "SELECT * from texttable(file columns x string WIDTH 1 NO TRIM NO ROW DELIMITER) as x"; //$NON-NLS-1$
         helpTest(QueryParser.getQueryParser().parseCommand(sql), "SELECT * FROM TEXTTABLE(file COLUMNS x string WIDTH 1 NO TRIM NO ROW DELIMITER) AS x");
     }
+    
+    @Test public void testArray() {
+    	Array array = new Array(TypeFacility.RUNTIME_TYPES.INTEGER, Arrays.asList(new ElementSymbol("e1"), new Constant(1)));
+        helpTest(array, "(e1, 1)");             //$NON-NLS-1$
+    }
 
 }



More information about the teiid-commits mailing list