[teiid-commits] teiid SVN: r3339 - in trunk: connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/derby and 23 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Wed Jul 27 10:43:29 EDT 2011


Author: shawkins
Date: 2011-07-27 10:43:28 -0400 (Wed, 27 Jul 2011)
New Revision: 3339

Added:
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/db2/BaseDB2ExecutionFactory.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/RankingFunction.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/WindowFunctionProjectNode.java
   trunk/engine/src/test/java/org/teiid/query/processor/TestWindowFunctions.java
Modified:
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/db2/DB2ExecutionFactory.java
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/derby/DerbyExecutionFactory.java
   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/sqlserver/SQLServerExecutionFactory.java
   trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/teiid/TeiidExecutionFactory.java
   trunk/engine/src/main/java/org/teiid/common/buffer/STree.java
   trunk/engine/src/main/java/org/teiid/common/buffer/TupleBuffer.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/MetaDataProcessor.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourcePlanToProcessConverter.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/AggregateFunction.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/ArrayAgg.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/ConstantFunction.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PlanToProcessConverter.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/FrameUtil.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
   trunk/engine/src/main/java/org/teiid/query/processor/BatchCollector.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/ProjectNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/SortUtility.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/XMLTableNode.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/WindowFunction.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java
   trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
   trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
   trunk/engine/src/main/resources/org/teiid/query/i18n.properties
   trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java
   trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestMetaDataProcessor.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java
   trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
   trunk/engine/src/test/java/org/teiid/query/processor/TestAggregateProcessing.java
   trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java
   trunk/engine/src/test/java/org/teiid/query/processor/relational/TestGroupingNode.java
   trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
Log:
TEIID-1667 finishing initial implementation forward merge of TEIID-1688 TEIID-1682 TEIID-1681

Added: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/db2/BaseDB2ExecutionFactory.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/db2/BaseDB2ExecutionFactory.java	                        (rev 0)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/db2/BaseDB2ExecutionFactory.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -0,0 +1,176 @@
+/*
+ * 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.translator.jdbc.db2;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.teiid.language.DerivedColumn;
+import org.teiid.language.Expression;
+import org.teiid.language.Function;
+import org.teiid.language.Join;
+import org.teiid.language.LanguageFactory;
+import org.teiid.language.LanguageObject;
+import org.teiid.language.Limit;
+import org.teiid.language.Literal;
+import org.teiid.language.Comparison.Operator;
+import org.teiid.language.Join.JoinType;
+import org.teiid.translator.ExecutionContext;
+import org.teiid.translator.SourceSystemFunctions;
+import org.teiid.translator.TranslatorException;
+import org.teiid.translator.TypeFacility;
+import org.teiid.translator.jdbc.AliasModifier;
+import org.teiid.translator.jdbc.ConvertModifier;
+import org.teiid.translator.jdbc.FunctionModifier;
+import org.teiid.translator.jdbc.JDBCExecutionFactory;
+import org.teiid.translator.jdbc.LocateFunctionModifier;
+import org.teiid.translator.jdbc.ModFunctionModifier;
+
+public class BaseDB2ExecutionFactory extends JDBCExecutionFactory {
+
+	private final class NullHandlingFormatModifier extends
+			ConvertModifier.FormatModifier {
+		private NullHandlingFormatModifier(String alias) {
+			super(alias);
+		}
+
+		@Override
+		public List<?> translate(Function function) {
+			Expression arg = function.getParameters().get(0);
+			if (arg instanceof Literal && ((Literal)arg).getValue() == null) {
+				((Literal)function.getParameters().get(1)).setValue(this.alias);
+				return null;
+			}
+			return super.translate(function);
+		}
+	}
+
+	@Override
+	public void start() throws TranslatorException {
+		super.start();
+        registerFunctionModifier(SourceSystemFunctions.CHAR, new AliasModifier("chr")); //$NON-NLS-1$ 
+        registerFunctionModifier(SourceSystemFunctions.DAYOFMONTH, new AliasModifier("day")); //$NON-NLS-1$ 
+        registerFunctionModifier(SourceSystemFunctions.IFNULL, new AliasModifier("coalesce")); //$NON-NLS-1$ 
+        registerFunctionModifier(SourceSystemFunctions.LOCATE, new LocateFunctionModifier(getLanguageFactory()));
+        registerFunctionModifier(SourceSystemFunctions.SUBSTRING, new SubstringFunctionModifier());  
+
+        registerFunctionModifier(SourceSystemFunctions.MOD, new ModFunctionModifier("MOD", getLanguageFactory()));  //$NON-NLS-1$
+        
+        //add in type conversion
+        ConvertModifier convertModifier = new ConvertModifier();
+    	convertModifier.addTypeMapping("real", FunctionModifier.FLOAT); //$NON-NLS-1$
+    	convertModifier.addTypeMapping("numeric(31,0)", FunctionModifier.BIGINTEGER); //$NON-NLS-1$
+    	convertModifier.addTypeMapping("numeric(31,12)", FunctionModifier.BIGDECIMAL); //$NON-NLS-1$
+    	convertModifier.addTypeMapping("char(1)", FunctionModifier.CHAR); //$NON-NLS-1$
+    	convertModifier.addTypeMapping("blob", FunctionModifier.BLOB, FunctionModifier.OBJECT); //$NON-NLS-1$
+    	convertModifier.addTypeMapping("clob", FunctionModifier.CLOB, FunctionModifier.XML); //$NON-NLS-1$
+    	convertModifier.addConvert(FunctionModifier.TIME, FunctionModifier.TIMESTAMP, new FunctionModifier() {
+			@Override
+			public List<?> translate(Function function) {
+				return Arrays.asList("timestamp('1970-01-01', ", function.getParameters().get(0), ")"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		});
+    	convertModifier.addConvert(FunctionModifier.DATE, FunctionModifier.TIMESTAMP, new FunctionModifier() {
+			@Override
+			public List<?> translate(Function function) {
+				return Arrays.asList("timestamp(",function.getParameters().get(0), ", '00:00:00')"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		});
+    	//the next convert is not strictly necessary for db2, but it also works for derby
+    	convertModifier.addConvert(FunctionModifier.STRING, FunctionModifier.FLOAT, new FunctionModifier() {
+			@Override
+			public List<?> translate(Function function) {
+				return Arrays.asList("cast(double(", function.getParameters().get(0), ") as real)"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		});
+    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("char"), FunctionModifier.STRING); //$NON-NLS-1$
+    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("smallint"), FunctionModifier.BYTE, FunctionModifier.SHORT); //$NON-NLS-1$
+    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("integer"), FunctionModifier.INTEGER); //$NON-NLS-1$
+    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("bigint"), FunctionModifier.LONG); //$NON-NLS-1$
+    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("double"), FunctionModifier.DOUBLE); //$NON-NLS-1$
+    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("date"), FunctionModifier.DATE); //$NON-NLS-1$
+    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("time"), FunctionModifier.TIME); //$NON-NLS-1$
+    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("timestamp"), FunctionModifier.TIMESTAMP); //$NON-NLS-1$
+    	convertModifier.addNumericBooleanConversions();
+    	registerFunctionModifier(SourceSystemFunctions.CONVERT, convertModifier);
+    }
+		
+	@SuppressWarnings("unchecked")
+	@Override
+	public List<?> translateLimit(Limit limit, ExecutionContext context) {
+		return Arrays.asList("FETCH FIRST ", limit.getRowLimit(), " ROWS ONLY"); //$NON-NLS-1$ //$NON-NLS-2$ 
+	}
+	
+	@Override
+	public List<?> translate(LanguageObject obj, ExecutionContext context) {
+		//DB2 doesn't support cross join
+		convertCrossJoinToInner(obj, getLanguageFactory());
+		//DB2 needs projected nulls wrapped in casts
+		if (obj instanceof DerivedColumn) {
+			DerivedColumn selectSymbol = (DerivedColumn)obj;
+			if (selectSymbol.getExpression() instanceof Literal) {
+				Literal literal = (Literal)selectSymbol.getExpression();
+				if (literal.getValue() == null) {
+					String type = TypeFacility.RUNTIME_NAMES.INTEGER;
+					if (literal.getType() != TypeFacility.RUNTIME_TYPES.NULL) {
+						type = TypeFacility.getDataTypeName(literal.getType());
+					}
+					selectSymbol.setExpression(ConvertModifier.createConvertFunction(getLanguageFactory(), literal, type));
+				}
+			}
+		}
+		return super.translate(obj, context);
+	}
+
+	public static void convertCrossJoinToInner(LanguageObject obj, LanguageFactory lf) {
+		if (obj instanceof Join) {
+			Join join = (Join)obj;
+			if (join.getJoinType() == JoinType.CROSS_JOIN) {
+				Literal one = lf.createLiteral(1, TypeFacility.RUNTIME_TYPES.INTEGER);
+				join.setCondition(lf.createCompareCriteria(Operator.EQ, one, one));
+				join.setJoinType(JoinType.INNER_JOIN);
+			}
+		}
+	}
+	
+	@Override
+	public NullOrder getDefaultNullOrder() {
+		return NullOrder.HIGH;
+	}
+	
+	@Override
+	public boolean supportsInlineViews() {
+		return true;
+	}
+
+	@Override
+	public boolean supportsExcept() {
+		return true;
+	}
+
+	@Override
+	public boolean supportsIntersect() {
+		return true;
+	}
+	
+}


Property changes on: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/db2/BaseDB2ExecutionFactory.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/db2/DB2ExecutionFactory.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/db2/DB2ExecutionFactory.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/db2/DB2ExecutionFactory.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -23,142 +23,18 @@
 package org.teiid.translator.jdbc.db2;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
-import org.teiid.language.DerivedColumn;
-import org.teiid.language.Expression;
-import org.teiid.language.Function;
-import org.teiid.language.Join;
-import org.teiid.language.LanguageFactory;
-import org.teiid.language.LanguageObject;
-import org.teiid.language.Limit;
-import org.teiid.language.Literal;
-import org.teiid.language.Comparison.Operator;
-import org.teiid.language.Join.JoinType;
-import org.teiid.translator.ExecutionContext;
-import org.teiid.translator.SourceSystemFunctions;
 import org.teiid.translator.Translator;
-import org.teiid.translator.TranslatorException;
-import org.teiid.translator.TypeFacility;
-import org.teiid.translator.jdbc.AliasModifier;
-import org.teiid.translator.jdbc.ConvertModifier;
-import org.teiid.translator.jdbc.FunctionModifier;
-import org.teiid.translator.jdbc.JDBCExecutionFactory;
-import org.teiid.translator.jdbc.LocateFunctionModifier;
-import org.teiid.translator.jdbc.ModFunctionModifier;
 
 @Translator(name="db2", description="A translator for IBM DB2 Database")
-public class DB2ExecutionFactory extends JDBCExecutionFactory {
-
-	private final class NullHandlingFormatModifier extends
-			ConvertModifier.FormatModifier {
-		private NullHandlingFormatModifier(String alias) {
-			super(alias);
-		}
-
-		@Override
-		public List<?> translate(Function function) {
-			Expression arg = function.getParameters().get(0);
-			if (arg instanceof Literal && ((Literal)arg).getValue() == null) {
-				((Literal)function.getParameters().get(1)).setValue(this.alias);
-				return null;
-			}
-			return super.translate(function);
-		}
-	}
-
-	@Override
-	public void start() throws TranslatorException {
-		super.start();
-        registerFunctionModifier(SourceSystemFunctions.CHAR, new AliasModifier("chr")); //$NON-NLS-1$ 
-        registerFunctionModifier(SourceSystemFunctions.DAYOFMONTH, new AliasModifier("day")); //$NON-NLS-1$ 
-        registerFunctionModifier(SourceSystemFunctions.IFNULL, new AliasModifier("coalesce")); //$NON-NLS-1$ 
-        registerFunctionModifier(SourceSystemFunctions.LOCATE, new LocateFunctionModifier(getLanguageFactory()));
-        registerFunctionModifier(SourceSystemFunctions.SUBSTRING, new SubstringFunctionModifier());  
-
-        registerFunctionModifier(SourceSystemFunctions.MOD, new ModFunctionModifier("MOD", getLanguageFactory()));  //$NON-NLS-1$
-        
-        //add in type conversion
-        ConvertModifier convertModifier = new ConvertModifier();
-    	convertModifier.addTypeMapping("real", FunctionModifier.FLOAT); //$NON-NLS-1$
-    	convertModifier.addTypeMapping("numeric(31,0)", FunctionModifier.BIGINTEGER); //$NON-NLS-1$
-    	convertModifier.addTypeMapping("numeric(31,12)", FunctionModifier.BIGDECIMAL); //$NON-NLS-1$
-    	convertModifier.addTypeMapping("char(1)", FunctionModifier.CHAR); //$NON-NLS-1$
-    	convertModifier.addTypeMapping("blob", FunctionModifier.BLOB, FunctionModifier.OBJECT); //$NON-NLS-1$
-    	convertModifier.addTypeMapping("clob", FunctionModifier.CLOB, FunctionModifier.XML); //$NON-NLS-1$
-    	convertModifier.addConvert(FunctionModifier.TIME, FunctionModifier.TIMESTAMP, new FunctionModifier() {
-			@Override
-			public List<?> translate(Function function) {
-				return Arrays.asList("timestamp('1970-01-01', ", function.getParameters().get(0), ")"); //$NON-NLS-1$ //$NON-NLS-2$
-			}
-		});
-    	convertModifier.addConvert(FunctionModifier.DATE, FunctionModifier.TIMESTAMP, new FunctionModifier() {
-			@Override
-			public List<?> translate(Function function) {
-				return Arrays.asList("timestamp(",function.getParameters().get(0), ", '00:00:00')"); //$NON-NLS-1$ //$NON-NLS-2$
-			}
-		});
-    	//the next convert is not strictly necessary for db2, but it also works for derby
-    	convertModifier.addConvert(FunctionModifier.STRING, FunctionModifier.FLOAT, new FunctionModifier() {
-			@Override
-			public List<?> translate(Function function) {
-				return Arrays.asList("cast(double(", function.getParameters().get(0), ") as real)"); //$NON-NLS-1$ //$NON-NLS-2$
-			}
-		});
-    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("char"), FunctionModifier.STRING); //$NON-NLS-1$
-    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("smallint"), FunctionModifier.BYTE, FunctionModifier.SHORT); //$NON-NLS-1$
-    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("integer"), FunctionModifier.INTEGER); //$NON-NLS-1$
-    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("bigint"), FunctionModifier.LONG); //$NON-NLS-1$
-    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("double"), FunctionModifier.DOUBLE); //$NON-NLS-1$
-    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("date"), FunctionModifier.DATE); //$NON-NLS-1$
-    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("time"), FunctionModifier.TIME); //$NON-NLS-1$
-    	convertModifier.addTypeConversion(new NullHandlingFormatModifier("timestamp"), FunctionModifier.TIMESTAMP); //$NON-NLS-1$
-    	convertModifier.addNumericBooleanConversions();
-    	registerFunctionModifier(SourceSystemFunctions.CONVERT, convertModifier);
-    }
-		
-	@SuppressWarnings("unchecked")
-	@Override
-	public List<?> translateLimit(Limit limit, ExecutionContext context) {
-		return Arrays.asList("FETCH FIRST ", limit.getRowLimit(), " ROWS ONLY"); //$NON-NLS-1$ //$NON-NLS-2$ 
-	}
+public class DB2ExecutionFactory extends BaseDB2ExecutionFactory {
 	
-	@Override
-	public List<?> translate(LanguageObject obj, ExecutionContext context) {
-		//DB2 doesn't support cross join
-		convertCrossJoinToInner(obj, getLanguageFactory());
-		//DB2 needs projected nulls wrapped in casts
-		if (obj instanceof DerivedColumn) {
-			DerivedColumn selectSymbol = (DerivedColumn)obj;
-			if (selectSymbol.getExpression() instanceof Literal) {
-				Literal literal = (Literal)selectSymbol.getExpression();
-				if (literal.getValue() == null) {
-					String type = TypeFacility.RUNTIME_NAMES.INTEGER;
-					if (literal.getType() != TypeFacility.RUNTIME_TYPES.NULL) {
-						type = TypeFacility.getDataTypeName(literal.getType());
-					}
-					selectSymbol.setExpression(ConvertModifier.createConvertFunction(getLanguageFactory(), literal, type));
-				}
-			}
-		}
-		return super.translate(obj, context);
-	}
-
-	public static void convertCrossJoinToInner(LanguageObject obj, LanguageFactory lf) {
-		if (obj instanceof Join) {
-			Join join = (Join)obj;
-			if (join.getJoinType() == JoinType.CROSS_JOIN) {
-				Literal one = lf.createLiteral(1, TypeFacility.RUNTIME_TYPES.INTEGER);
-				join.setCondition(lf.createCompareCriteria(Operator.EQ, one, one));
-				join.setJoinType(JoinType.INNER_JOIN);
-			}
-		}
-	}
+	public static final String EIGHT_0 = "8.0"; //$NON-NLS-1$
+	public static final String NINE_1 = "9.1"; //$NON-NLS-1$
 	
-	@Override
-	public NullOrder getDefaultNullOrder() {
-		return NullOrder.HIGH;
+	public DB2ExecutionFactory() {
+		setDatabaseVersion(EIGHT_0);
 	}
 	
 	@Override
@@ -228,39 +104,30 @@
 		supportedFunctions.add("COALESCE"); //$NON-NLS-1$
 		return supportedFunctions;
 	}
-
+
 	@Override
-	public boolean supportsInlineViews() {
-		return true;
-	}
-
-	@Override
 	public boolean supportsFunctionsInGroupBy() {
 		return true;
 	}
 
 	@Override
-	public boolean supportsRowLimit() {
+	public boolean supportsAggregatesEnhancedNumeric() {
 		return true;
 	}
-
+	
 	@Override
-	public boolean supportsExcept() {
+	public boolean supportsCommonTableExpressions() {
 		return true;
 	}
-
-	@Override
-	public boolean supportsIntersect() {
-		return true;
-	}
 	
 	@Override
-	public boolean supportsAggregatesEnhancedNumeric() {
+	public boolean supportsRowLimit() {
 		return true;
 	}
 	
 	@Override
-	public boolean supportsCommonTableExpressions() {
-		return true;
-	}
+	public boolean supportsElementaryOlapOperations() {
+		return getDatabaseVersion().compareTo(NINE_1) >= 0;
+	}
+
 }

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/derby/DerbyExecutionFactory.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/derby/DerbyExecutionFactory.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/derby/DerbyExecutionFactory.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -29,14 +29,14 @@
 import org.teiid.translator.Translator;
 import org.teiid.translator.TranslatorException;
 import org.teiid.translator.jdbc.EscapeSyntaxModifier;
-import org.teiid.translator.jdbc.db2.DB2ExecutionFactory;
+import org.teiid.translator.jdbc.db2.BaseDB2ExecutionFactory;
 import org.teiid.translator.jdbc.oracle.LeftOrRightFunctionModifier;
 
 /** 
  * @since 4.3
  */
 @Translator(name="derby", description="A translator for Apache Derby Database")
-public class DerbyExecutionFactory extends DB2ExecutionFactory {
+public class DerbyExecutionFactory extends BaseDB2ExecutionFactory {
 	
 	public static final String TEN_1 = "10.1"; //$NON-NLS-1$
 	public static final String TEN_2 = "10.2"; //$NON-NLS-1$
@@ -181,8 +181,4 @@
     	return this.getDatabaseVersion().compareTo(TEN_5) >= 0;
     }
     
-	@Override
-	public boolean supportsFunctionsInGroupBy() {
-		return false;
-	}
 }

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	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/oracle/OracleExecutionFactory.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -532,4 +532,9 @@
     	return true;
     }
     
+    @Override
+    public boolean supportsElementaryOlapOperations() {
+    	return true;
+    }
+    
 }

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/sqlserver/SQLServerExecutionFactory.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/sqlserver/SQLServerExecutionFactory.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/sqlserver/SQLServerExecutionFactory.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -226,5 +226,10 @@
     protected boolean supportsCrossJoin() {
     	return true;
     }
+    
+    @Override
+    public boolean supportsElementaryOlapOperations() {
+    	return true;
+    }
     
 }

Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/teiid/TeiidExecutionFactory.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/teiid/TeiidExecutionFactory.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/teiid/TeiidExecutionFactory.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -42,6 +42,7 @@
 	public static final String SEVEN_2 = "7.2"; //$NON-NLS-1$
 	public static final String SEVEN_3 = "7.3"; //$NON-NLS-1$
 	public static final String SEVEN_4 = "7.4"; //$NON-NLS-1$
+	public static final String SEVEN_5 = "7.5"; //$NON-NLS-1$
 	
 	public TeiidExecutionFactory() {
 		setDatabaseVersion(SEVEN_0);
@@ -201,4 +202,19 @@
     public boolean supportsCommonTableExpressions() {
     	return getDatabaseVersion().compareTo(SEVEN_2) >= 0;
     }
+    
+    @Override
+    public boolean supportsAdvancedOlapOperations() {
+    	return getDatabaseVersion().compareTo(SEVEN_5) >= 0;
+    }
+    
+    @Override
+    public boolean supportsElementaryOlapOperations() {
+    	return getDatabaseVersion().compareTo(SEVEN_5) >= 0;
+    }
+    
+    @Override
+    public boolean supportsArrayAgg() {
+    	return getDatabaseVersion().compareTo(SEVEN_5) >= 0;
+    }
 }

Modified: trunk/engine/src/main/java/org/teiid/common/buffer/STree.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/STree.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/STree.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -169,6 +169,10 @@
 		return null;
 	}
 	
+	public List find(List n) throws TeiidComponentException {
+		return find(n, new LinkedList<SearchResult>());
+	}
+	
 	public List insert(List tuple, InsertMode mode, int sizeHint) throws TeiidComponentException {
 		LinkedList<SearchResult> places = new LinkedList<SearchResult>();
 		List match = null;

Modified: trunk/engine/src/main/java/org/teiid/common/buffer/TupleBuffer.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/TupleBuffer.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/TupleBuffer.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -48,13 +48,13 @@
      * @return
      * @since 4.2
      */
-    public static String[] getTypeNames(List expressions) {
+    public static String[] getTypeNames(List<? extends Expression> expressions) {
     	if (expressions == null) {
     		return null;
     	}
         String[] types = new String[expressions.size()];
-        for (ListIterator i = expressions.listIterator(); i.hasNext();) {
-            Expression expr = (Expression)i.next();
+        for (ListIterator<? extends Expression> i = expressions.listIterator(); i.hasNext();) {
+            Expression expr = i.next();
             types[i.previousIndex()] = DataTypeManager.getDataTypeName(expr.getType());
         }
         return types;
@@ -63,7 +63,7 @@
 	//construction state
 	private BatchManager manager;
 	private String tupleSourceID;
-	private List<?> schema;
+	private List<? extends Expression> schema;
 	private String[] types;
 	private int batchSize;
 	
@@ -80,7 +80,7 @@
 	private String uuid;
 	private FileStore lobStore;
 	
-	public TupleBuffer(BatchManager manager, String id, List<?> schema, int[] lobIndexes, int batchSize) {
+	public TupleBuffer(BatchManager manager, String id, List<? extends Expression> schema, int[] lobIndexes, int batchSize) {
 		this.manager = manager;
 		this.tupleSourceID = id;
 		this.schema = schema;
@@ -276,7 +276,7 @@
 		this.isFinal = isFinal;
 	}
 	
-	public List<?> getSchema() {
+	public List<? extends Expression> getSchema() {
 		return schema;
 	}
 	

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -192,24 +192,17 @@
                 symbol = ((AliasSymbol)symbol).getSymbol();
             }
 
-            org.teiid.language.Expression iExp = null;
-            if(symbol instanceof ElementSymbol) {
-                iExp = translate((ElementSymbol)symbol);
-            } else if(symbol instanceof AggregateSymbol) {
-                iExp = translate((AggregateSymbol)symbol);
-            } else if(symbol instanceof ExpressionSymbol) {
-                iExp = translate(((ExpressionSymbol)symbol).getExpression());
-            }
+            org.teiid.language.Expression iExp = translate(symbol);
 
             DerivedColumn selectSymbol = new DerivedColumn(alias, iExp);
             translatedSymbols.add(selectSymbol);
         }
     	List<TableReference> items = null;
     	if (query.getFrom() != null) {
-	    	List clauses = query.getFrom().getClauses();
+	    	List<FromClause> clauses = query.getFrom().getClauses();
 	        items = new ArrayList<TableReference>(clauses.size());
-	        for (Iterator i = clauses.iterator(); i.hasNext();) {
-	            items.add(translate((FromClause)i.next()));
+	        for (Iterator<FromClause> i = clauses.iterator(); i.hasNext();) {
+	            items.add(translate(i.next()));
 	        }
     	}
 		Select q = new Select(translatedSymbols, query
@@ -485,8 +478,12 @@
             return translate((ScalarSubquery)expr);
         } else if (expr instanceof SearchedCaseExpression) {
             return translate((SearchedCaseExpression)expr);
-        } else if (expr instanceof SingleElementSymbol) {
-            return translate((SingleElementSymbol)expr);
+        } else if (expr instanceof ElementSymbol) {
+            return translate((ElementSymbol)expr);
+        } else if (expr instanceof AggregateSymbol) {
+            return translate((AggregateSymbol)expr);
+        } else if (expr instanceof ExpressionSymbol) {
+            return translate((ExpressionSymbol)expr);
         } else if (expr instanceof Criteria) {
         	return translate((Criteria)expr);
         } else if (expr instanceof WindowFunction) {
@@ -563,18 +560,6 @@
         return new org.teiid.language.ScalarSubquery(translate(ss.getCommand()));
     }
 
-    org.teiid.language.Expression translate(SingleElementSymbol symbol) {
-        if (symbol == null) return null;
-        if (symbol instanceof ElementSymbol) {
-            return translate((ElementSymbol)symbol);
-        } else if (symbol instanceof AggregateSymbol) {
-            return translate((AggregateSymbol)symbol);
-        } else if (symbol instanceof ExpressionSymbol) {
-            return translate((ExpressionSymbol)symbol);
-        }
-        throw new AssertionError();
-    }
-
     org.teiid.language.Expression translate(AliasSymbol symbol) {
         return translate(symbol.getSymbol());
     }
@@ -604,7 +589,6 @@
         return translate(symbol.getExpression());
     }
 
-
     /* Insert */
     org.teiid.language.Insert translate(Insert insert) {
         List<ElementSymbol> elements = insert.getVariables();

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/MetaDataProcessor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/MetaDataProcessor.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/MetaDataProcessor.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -58,6 +58,7 @@
 import org.teiid.query.sql.symbol.GroupSymbol;
 import org.teiid.query.sql.symbol.Reference;
 import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.symbol.WindowFunction;
 import org.teiid.query.sql.symbol.AggregateSymbol.Type;
 import org.teiid.query.sql.visitor.ReferenceCollectorVisitor;
 import org.teiid.query.tempdata.TempTableStore;
@@ -231,6 +232,8 @@
             return createElementMetadata(label, (ElementSymbol) symbol);        
         } else if(symbol instanceof AggregateSymbol) {
             return createAggregateMetadata(label, (AggregateSymbol) symbol);
+        } else if (symbol instanceof WindowFunction) {
+        	return createAggregateMetadata(label, ((WindowFunction) symbol).getFunction());
         }
         return createTypedMetadata(label, symbol);            
     }

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourcePlanToProcessConverter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourcePlanToProcessConverter.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/multisource/MultiSourcePlanToProcessConverter.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -209,7 +209,7 @@
             		update = true;
             		GroupingNode groupNode = new GroupingNode(getID());                    
             		AggregateSymbol sumCount = new AggregateSymbol("SumCount", NonReserved.SUM, false, (Expression)accessNode.getElements().get(0)); //$NON-NLS-1$          		
-            		List<Expression> outputElements = new ArrayList<Expression>(1);            		
+            		List<SingleElementSymbol> outputElements = new ArrayList<SingleElementSymbol>(1);            		
             		outputElements.add(sumCount); 
             		groupNode.setElements(outputElements);
             		groupNode.addChild(unionNode);
@@ -218,8 +218,8 @@
             		
             		Expression intSum = ResolverUtil.getConversion(sumCount, DataTypeManager.getDataTypeName(sumCount.getType()), DataTypeManager.DefaultDataTypes.INTEGER, false, metadata.getFunctionLibrary());
             		
-            		Expression rowCount = new ExpressionSymbol("RowCount", intSum); //$NON-NLS-1$            		
-            		outputElements = new ArrayList<Expression>(1);            		
+            		ExpressionSymbol rowCount = new ExpressionSymbol("RowCount", intSum); //$NON-NLS-1$            		
+            		outputElements = new ArrayList<SingleElementSymbol>(1);            		
             		outputElements.add(rowCount);             		
             		projectNode.setElements(outputElements);
             		projectNode.setSelectSymbols(outputElements);

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/AggregateFunction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/AggregateFunction.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/AggregateFunction.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -39,10 +39,15 @@
 public abstract class AggregateFunction {
 
 	private int expressionIndex = -1;
+	private int conditionIndex = -1;
 	
 	public void setExpressionIndex(int expressionIndex) {
 		this.expressionIndex = expressionIndex;
 	}
+	
+	public void setConditionIndex(int conditionIndex) {
+		this.conditionIndex = conditionIndex;
+	}
 
     /**
      * Called to initialize the function.  In the future this may expand
@@ -58,18 +63,21 @@
     public abstract void reset();
 
     public void addInput(List<?> tuple) throws TeiidComponentException, TeiidProcessingException {
+    	if (conditionIndex != -1 && !Boolean.TRUE.equals(tuple.get(conditionIndex))) {
+			return;
+    	}
     	if (expressionIndex == -1) {
     		addInputDirect(null, tuple);
     		return;
     	}
     	Object input = tuple.get(expressionIndex);
-    	if (!filter(input)) {
+    	if (input != null || respectsNull()) {
     		addInputDirect(input, tuple);
     	}
     }
     
-    boolean filter(Object value) {
-    	return value == null; 
+    public boolean respectsNull() {
+    	return false;
     }
     
     /**

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/ArrayAgg.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/ArrayAgg.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/ArrayAgg.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -62,10 +62,10 @@
 	public void reset() {
 		this.result = null;
 	}
+	
+	@Override
+	public boolean respectsNull() {
+		return true;
+	}
 
-	@Override
-    boolean filter(Object value) {
-		// handle the null values too.
-    	return false; 
-    }	
 }

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/ConstantFunction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/ConstantFunction.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/ConstantFunction.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -40,8 +40,8 @@
     }
     
     @Override
-    boolean filter(Object input) {
-    	return false;
+    public boolean respectsNull() {
+    	return true;
     }
 
     /**

Added: trunk/engine/src/main/java/org/teiid/query/function/aggregate/RankingFunction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/RankingFunction.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/RankingFunction.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -0,0 +1,74 @@
+/*
+ * 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.function.aggregate;
+
+import java.util.List;
+
+import org.teiid.api.exception.query.ExpressionEvaluationException;
+import org.teiid.api.exception.query.FunctionExecutionException;
+import org.teiid.core.TeiidComponentException;
+import org.teiid.query.processor.relational.GroupingNode;
+import org.teiid.query.sql.symbol.AggregateSymbol.Type;
+
+/**
+ * computes rank/dense_rank
+ */
+public class RankingFunction extends AggregateFunction {
+	
+	private int count = 0;
+	private int result = 0;
+	private int[] orderIndexes;
+	private Type type;
+	private List<?> previousTuple;
+	
+	public RankingFunction(Type function, int[] orderIndexes) {
+		this.type = function;
+		this.orderIndexes = orderIndexes;
+	}
+
+	@Override
+	public void reset() {
+		count = 0;
+		result = 0;
+	}
+	
+	@Override
+	public void addInputDirect(Object input, List<?> tuple)
+			throws FunctionExecutionException, ExpressionEvaluationException,
+			TeiidComponentException {
+		if (previousTuple == null || !GroupingNode.sameGroup(orderIndexes, tuple, previousTuple)) {
+			count++;
+			result = count;
+		} else if (type == Type.RANK) {
+			count++;
+		}
+		previousTuple = tuple;
+	}
+	
+	@Override
+	public Object getResult() throws FunctionExecutionException,
+			ExpressionEvaluationException, TeiidComponentException {
+		return result;
+	}
+
+}


Property changes on: trunk/engine/src/main/java/org/teiid/query/function/aggregate/RankingFunction.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PlanToProcessConverter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PlanToProcessConverter.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PlanToProcessConverter.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -26,6 +26,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.api.exception.query.QueryPlannerException;
@@ -45,6 +46,8 @@
 import org.teiid.query.optimizer.relational.plantree.NodeConstants.Info;
 import org.teiid.query.optimizer.relational.rules.CapabilitiesUtil;
 import org.teiid.query.optimizer.relational.rules.FrameUtil;
+import org.teiid.query.optimizer.relational.rules.RuleAssignOutputElements;
+import org.teiid.query.optimizer.relational.rules.RuleChooseJoinStrategy;
 import org.teiid.query.processor.ProcessorPlan;
 import org.teiid.query.processor.relational.AccessNode;
 import org.teiid.query.processor.relational.ArrayTableNode;
@@ -69,6 +72,7 @@
 import org.teiid.query.processor.relational.SortNode;
 import org.teiid.query.processor.relational.TextTableNode;
 import org.teiid.query.processor.relational.UnionAllNode;
+import org.teiid.query.processor.relational.WindowFunctionProjectNode;
 import org.teiid.query.processor.relational.XMLTableNode;
 import org.teiid.query.processor.relational.JoinNode.JoinStrategyType;
 import org.teiid.query.processor.relational.MergeJoinStrategy.SortOption;
@@ -80,6 +84,7 @@
 import org.teiid.query.sql.lang.Insert;
 import org.teiid.query.sql.lang.JoinType;
 import org.teiid.query.sql.lang.OrderBy;
+import org.teiid.query.sql.lang.OrderByItem;
 import org.teiid.query.sql.lang.Query;
 import org.teiid.query.sql.lang.QueryCommand;
 import org.teiid.query.sql.lang.StoredProcedure;
@@ -90,7 +95,10 @@
 import org.teiid.query.sql.lang.XMLTable.XMLColumn;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
+import org.teiid.query.sql.symbol.ExpressionSymbol;
 import org.teiid.query.sql.symbol.GroupSymbol;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.symbol.WindowFunction;
 import org.teiid.query.sql.util.SymbolMap;
 import org.teiid.query.sql.visitor.EvaluatableVisitor;
 import org.teiid.query.sql.visitor.GroupCollectorVisitor;
@@ -213,11 +221,25 @@
                     }
 
                 } else {
-                    List symbols = (List) node.getProperty(NodeConstants.Info.PROJECT_COLS);
+                    List<SingleElementSymbol> symbols = (List) node.getProperty(NodeConstants.Info.PROJECT_COLS);
                     
                     ProjectNode pnode = new ProjectNode(getID());
                     pnode.setSelectSymbols(symbols);
             		processNode = pnode;
+            		
+            		if (node.hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
+            			WindowFunctionProjectNode wfpn = new WindowFunctionProjectNode(getID());
+            			Set<WindowFunction> windowFunctions = RuleAssignOutputElements.getWindowFunctions(symbols);
+            			//TODO: check for selecting all window functions
+            			List<SingleElementSymbol> outputElements = new ArrayList<SingleElementSymbol>(windowFunctions);
+            			//collect the other projected expressions
+            			for (SingleElementSymbol singleElementSymbol : (List<SingleElementSymbol>)node.getFirstChild().getProperty(Info.OUTPUT_COLS)) {
+							outputElements.add(singleElementSymbol);
+						}
+            			wfpn.setElements(outputElements);
+            			wfpn.init();
+            			pnode.addChild(wfpn);
+            		}
                 }
                 break;
 
@@ -374,9 +396,32 @@
 				break;
 			case NodeConstants.Types.GROUP:
 				GroupingNode gnode = new GroupingNode(getID());
-				gnode.setGroupingElements( (List<Expression>) node.getProperty(NodeConstants.Info.GROUP_COLS) );
-				gnode.setOutputMapping((SymbolMap)node.getProperty(NodeConstants.Info.SYMBOL_MAP));
+				SymbolMap groupingMap = (SymbolMap)node.getProperty(NodeConstants.Info.SYMBOL_MAP);
+				gnode.setOutputMapping(groupingMap);
 				gnode.setRemoveDuplicates(node.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL));
+				List<Expression> gCols = (List) node.getProperty(NodeConstants.Info.GROUP_COLS);
+				orderBy = (OrderBy) node.getProperty(Info.SORT_ORDER);
+				if (orderBy == null) {
+			        if (gCols != null) {
+		                orderBy = new OrderBy(RuleChooseJoinStrategy.createExpressionSymbols(gCols));
+			        }
+				} else {
+			        for (int i = 0; i < gCols.size(); i++) {
+			        	if (i < orderBy.getOrderByItems().size()) {
+			        		OrderByItem orderByItem = orderBy.getOrderByItems().get(i);
+							Expression ex = SymbolMap.getExpression(orderByItem.getSymbol());
+				        	if (ex instanceof ElementSymbol) {
+			            		ex = groupingMap.getMappedExpression((ElementSymbol) ex);
+			            		orderByItem.setSymbol(new ExpressionSymbol("expr", ex)); //$NON-NLS-1$
+			            	}
+			        	} else {
+			        		orderBy.addVariable(new ExpressionSymbol("expr", gCols.get(i)), OrderBy.ASC); //$NON-NLS-1$
+			        	}
+			        }
+				}
+				if (orderBy != null) {
+			        gnode.setOrderBy(orderBy.getOrderByItems());
+				}
 				processNode = gnode;
 				break;
 

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/FrameUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/FrameUtil.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/FrameUtil.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -285,7 +285,10 @@
             }               
             if (!singleMapping) {
                 //add back the anon group
-                groups.add(((SymbolMap)node.getProperty(Info.SYMBOL_MAP)).asMap().keySet().iterator().next().getGroupSymbol());
+                SymbolMap property = (SymbolMap)node.getProperty(Info.SYMBOL_MAP);
+                if (!property.asMap().isEmpty()) {
+                	groups.add(property.asMap().keySet().iterator().next().getGroupSymbol());
+                }
             }
         } else if (type == NodeConstants.Types.SOURCE || type == NodeConstants.Types.ACCESS) {
             convertAccessPatterns(symbolMap, node);

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -29,6 +29,7 @@
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.teiid.api.exception.query.QueryMetadataException;
@@ -59,7 +60,9 @@
 import org.teiid.query.sql.symbol.ExpressionSymbol;
 import org.teiid.query.sql.symbol.GroupSymbol;
 import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.symbol.WindowFunction;
 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.util.CommandContext;
@@ -210,6 +213,12 @@
 		            	root.addGroups(GroupsUsedByElementsVisitor.getGroups(projectCols));
 		            	root.addGroups(GroupsUsedByElementsVisitor.getGroups(root.getCorrelatedReferenceElements()));
 	            	}
+	            	if (root.hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
+	            		Set<WindowFunction> windowFunctions = getWindowFunctions(projectCols);
+	            		if (windowFunctions.isEmpty()) {
+	            			root.setProperty(Info.HAS_WINDOW_FUNCTIONS, false);
+	            		}
+	            	}
 		    	}
 	            
 	            List<SingleElementSymbol> requiredInput = collectRequiredInputSymbols(root);
@@ -220,7 +229,9 @@
 	            	NodeEditor.removeChildNode(root.getParent(), root);
 	            	
             		SymbolMap symbolMap = (SymbolMap) old.getProperty(NodeConstants.Info.SYMBOL_MAP);
-    				FrameUtil.convertFrame(next.getParent(), symbolMap.asMap().keySet().iterator().next().getGroupSymbol(), null, symbolMap.asMap(), metadata);
+            		if (!symbolMap.asMap().isEmpty()) {
+            			FrameUtil.convertFrame(next.getParent(), symbolMap.asMap().keySet().iterator().next().getGroupSymbol(), null, symbolMap.asMap(), metadata);
+            		}
     				PlanNode parent = next.getParent();
     				while (parent.getParent() != null && parent.getParent().getType() != NodeConstants.Types.SOURCE) {
     					parent = parent.getParent();
@@ -258,6 +269,15 @@
 		}
 	}
 
+	public static Set<WindowFunction> getWindowFunctions(
+			List<SingleElementSymbol> projectCols) {
+		LinkedHashSet<WindowFunction> windowFunctions = new LinkedHashSet<WindowFunction>();
+		for (SingleElementSymbol singleElementSymbol : projectCols) {
+			AggregateSymbolCollectorVisitor.getAggregates(singleElementSymbol, null, null, null, windowFunctions, null);
+		}
+		return windowFunctions;
+	}
+
     private List<SingleElementSymbol> filterElements(Collection<? extends SingleElementSymbol> requiredInput, Set<GroupSymbol> filterGroups) {
         List<SingleElementSymbol> filteredElements = new ArrayList<SingleElementSymbol>();
         for (SingleElementSymbol element : requiredInput) {
@@ -504,16 +524,18 @@
 				    	ElementCollectorVisitor.getElements(expression, requiredSymbols);
                     }
 				}
-				boolean hasAggregate = false;
 				SymbolMap symbolMap = (SymbolMap) node.getProperty(NodeConstants.Info.SYMBOL_MAP);
+				Set<ElementSymbol> usedAggregates = new HashSet<ElementSymbol>();
 				
 				// Take credit for creating any aggregates that are needed above
 				for (SingleElementSymbol outputSymbol : outputCols) {
+					if (!(outputSymbol instanceof ElementSymbol)) {
+						continue;
+					}
 					createdSymbols.add(outputSymbol);
 					Expression ex = symbolMap.getMappedExpression((ElementSymbol) outputSymbol);
 					if(ex instanceof AggregateSymbol) {
 					    AggregateSymbol agg = (AggregateSymbol)ex;
-					    hasAggregate = true;					    
 	                    Expression aggExpr = agg.getExpression();
 	                    if(aggExpr != null) {
 	                    	ElementCollectorVisitor.getElements(aggExpr, requiredSymbols);
@@ -526,9 +548,16 @@
 	                    if(condition != null) {
 	                    	ElementCollectorVisitor.getElements(condition, requiredSymbols);
 	                    }
+	                    usedAggregates.add((ElementSymbol) outputSymbol);
 					}
 				}
-				if (requiredSymbols.isEmpty() && !hasAggregate) {
+				//update the aggs in the symbolmap
+				for (Map.Entry<ElementSymbol, Expression> entry : new ArrayList<Map.Entry<ElementSymbol, Expression>>(symbolMap.asMap().entrySet())) {
+					if (entry.getValue() instanceof AggregateSymbol && !usedAggregates.contains(entry.getKey())) {
+						symbolMap.asUpdatableMap().remove(entry.getKey());
+					}
+				}
+				if (requiredSymbols.isEmpty() && usedAggregates.isEmpty()) {
 					node.setProperty(Info.IS_OPTIONAL, true);
 				}
 				break;

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -89,7 +89,8 @@
 			} else {
 				root = checkForProjectOptimization(node, root, metadata, capFinder, record);
 			}
-			List<SingleElementSymbol> orderColumns = ((OrderBy)node.getProperty(NodeConstants.Info.SORT_ORDER)).getSortKeys();
+			OrderBy orderBy = (OrderBy)node.getProperty(NodeConstants.Info.SORT_ORDER);
+			List<SingleElementSymbol> orderColumns = orderBy.getSortKeys();
 			List<Expression> sortExpressions = new ArrayList<Expression>(orderColumns.size());
 			PlanNode possibleSort = NodeEditor.findNodePreOrder(node, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE | NodeConstants.Types.ACCESS);
 			if (possibleSort != null) {
@@ -118,6 +119,7 @@
 						NodeEditor.removeChildNode(node.getParent(), node);
 						node = nextNode;
 					}
+					possibleSort.setProperty(Info.SORT_ORDER, orderBy);
 				}
 				break;
 			} 
@@ -132,8 +134,33 @@
 			if (!node.hasCollectionProperty(NodeConstants.Info.GROUP_COLS)) {
 				break;
 			}
-			if (mergeSortWithDupRemovalAcrossSource(node)) {
+			SymbolMap map = (SymbolMap)node.getProperty(Info.SYMBOL_MAP);
+			boolean cardinalityDependent = false;
+			boolean canOptimize = true;
+			for (Expression ex : map.asMap().values()) {
+				if (ex instanceof AggregateSymbol) {
+					AggregateSymbol agg = (AggregateSymbol)ex;
+					if (agg.isCardinalityDependent()) {
+						cardinalityDependent = true;
+						break;
+					}
+				} else if (!(ex instanceof ElementSymbol)) {
+					//there is an expression in the grouping columns
+					canOptimize = false;
+					break;
+				}
+			}
+			if (canOptimize && mergeSortWithDupRemovalAcrossSource(node)) {
 				node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true);
+				if (cardinalityDependent) {
+					PlanNode source = NodeEditor.findNodePreOrder(node, NodeConstants.Types.SOURCE);
+					List<SingleElementSymbol> sourceOutput = (List<SingleElementSymbol>)source.getProperty(Info.OUTPUT_COLS);
+					PlanNode child = node.getFirstChild();
+					while (child != source) {
+						child.setProperty(Info.OUTPUT_COLS, sourceOutput);
+						child = child.getFirstChild();
+					}
+				}
 			}
 			//TODO: check the join interesting order
 			parentBlocking = true;

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -51,6 +51,7 @@
 import org.teiid.query.sql.symbol.Constant;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.symbol.Function;
+import org.teiid.query.sql.symbol.GroupSymbol;
 import org.teiid.query.sql.symbol.SearchedCaseExpression;
 import org.teiid.query.sql.visitor.EvaluatableVisitor;
 import org.teiid.query.util.CommandContext;
@@ -168,6 +169,13 @@
             }
             case NodeConstants.Types.SOURCE:
             {
+                GroupSymbol virtualGroup = child.getGroups().iterator().next();
+                if (virtualGroup.isProcedure()) {
+                        return false;
+                }
+                if (FrameUtil.isProcedure(child.getFirstChild())) {
+                    return false;
+                }
                 return true;
             }
             default:

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -44,6 +44,7 @@
 import org.teiid.query.optimizer.relational.plantree.NodeEditor;
 import org.teiid.query.optimizer.relational.plantree.NodeFactory;
 import org.teiid.query.optimizer.relational.plantree.PlanNode;
+import org.teiid.query.optimizer.relational.plantree.NodeConstants.Info;
 import org.teiid.query.sql.lang.CompareCriteria;
 import org.teiid.query.sql.lang.Criteria;
 import org.teiid.query.sql.lang.JoinType;
@@ -133,6 +134,12 @@
                 if (FrameUtil.isProcedure(parentNode)) {
                 	return null;
                 }
+                
+                PlanNode orderBy = NodeEditor.findParent(parentNode, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE);
+                if (orderBy != null && orderBy.hasBooleanProperty(Info.UNRELATED_SORT) && !canRaiseOverSort(accessNode, metadata, capFinder, orderBy, record, false)) {
+                	//this project node logically has the responsibility of creating the sort keys
+            		return null;
+                }
                                 
                 return performRaise(rootNode, accessNode, parentNode);                
             }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/BatchCollector.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/BatchCollector.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/processor/BatchCollector.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -78,7 +78,7 @@
 		}
 
 		@Override
-		public List<?> nextTuple() throws TeiidComponentException,
+		public List<Object> nextTuple() throws TeiidComponentException,
 				TeiidProcessingException {
 			while (true) {
 				if(sourceBatch == null) {
@@ -104,7 +104,7 @@
 		}
 		
 		@SuppressWarnings("unused")
-		protected List updateTuple(List tuple) throws ExpressionEvaluationException, BlockedException, TeiidComponentException {
+		protected List<?> updateTuple(List<?> tuple) throws ExpressionEvaluationException, BlockedException, TeiidComponentException {
 			return tuple;
 		}
 
@@ -150,7 +150,9 @@
             // Check for termination condition
             if(batch.getTerminationFlag()) {
             	done = true;
-            	buffer.close();
+            	if (!this.sourceNode.hasFinalBuffer()) {
+            		buffer.close();
+            	}
                 break;
             }
         }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -26,7 +26,6 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
@@ -41,6 +40,7 @@
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
 import org.teiid.language.SQLConstants.NonReserved;
+import org.teiid.language.SortSpecification.NullOrdering;
 import org.teiid.query.eval.Evaluator;
 import org.teiid.query.function.aggregate.AggregateFunction;
 import org.teiid.query.function.aggregate.ArrayAgg;
@@ -55,12 +55,14 @@
 import org.teiid.query.function.aggregate.XMLAgg;
 import org.teiid.query.processor.BatchCollector;
 import org.teiid.query.processor.ProcessorDataManager;
+import org.teiid.query.processor.BatchCollector.BatchProducer;
 import org.teiid.query.processor.relational.SortUtility.Mode;
 import org.teiid.query.sql.lang.OrderBy;
 import org.teiid.query.sql.lang.OrderByItem;
 import org.teiid.query.sql.symbol.AggregateSymbol;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
 import org.teiid.query.sql.symbol.TextLine;
 import org.teiid.query.sql.symbol.AggregateSymbol.Type;
 import org.teiid.query.sql.util.SymbolMap;
@@ -69,9 +71,34 @@
 
 public class GroupingNode extends RelationalNode {
 
-    // Grouping columns set by the planner 
-	private List<Expression> sortElements;
-	private List<Boolean> sortTypes;
+    static class ProjectingTupleSource extends
+			BatchCollector.BatchProducerTupleSource {
+    	
+    	private Evaluator eval;
+    	private List<Expression> collectedExpressions;
+    	
+		ProjectingTupleSource(BatchProducer sourceNode, Evaluator eval, List<Expression> expressions) {
+			super(sourceNode);
+			this.eval = eval;
+			this.collectedExpressions = expressions;
+		}
+
+		@Override
+		protected List<Object> updateTuple(List<?> tuple) throws ExpressionEvaluationException, BlockedException, TeiidComponentException {
+			int columns = collectedExpressions.size();
+		    List<Object> exprTuple = new ArrayList<Object>(columns);
+		    for(int col = 0; col<columns; col++) { 
+		        // The following call may throw BlockedException, but all state to this point
+		        // is saved in class variables so we can start over on building this tuple
+		        Object value = eval.evaluate(collectedExpressions.get(col), tuple);
+		        exprTuple.add(value);
+		    }
+		    return exprTuple;
+		}
+	}
+
+	// Grouping columns set by the planner 
+	private List<OrderByItem> orderBy;
 	private boolean removeDuplicates;
 	private SymbolMap outputMapping;
     
@@ -79,6 +106,7 @@
     private int phase = COLLECTION;
     private Map elementMap;                    // Map of incoming symbol to index in source elements
     private List<Expression> collectedExpressions;         // Collected Expressions
+    private int distinctCols = -1;
        
     // Sort phase
     private SortUtility sortUtility;
@@ -87,14 +115,14 @@
     
     // Group phase
     private AggregateFunction[] functions;
-    private int[] conditions;
-    private List lastRow;
-	private List currentGroupTuple;
+    private List<?> lastRow;
+	private List<?> currentGroupTuple;
 	private Evaluator eval;
 
     private static final int COLLECTION = 1;
     private static final int SORT = 2;
     private static final int GROUP = 3;
+	private int[] indexes;
 
 	public GroupingNode(int nodeID) {
 		super(nodeID);
@@ -122,19 +150,9 @@
 		this.removeDuplicates = removeDuplicates;
 	}
 
-    /**
-     * Called by the planner to initialize the grouping node.  Set the list of grouping
-     * expressions - these may be either elements or expressions and the list itself may
-     * be null to indicate an implied grouping on all columns
-     * @param groupingElements
-     * @since 4.2
-     */
-    public void setGroupingElements(List<Expression> groupingElements) {
-        this.sortElements = groupingElements;
-        if(groupingElements != null) {
-            sortTypes = Collections.nCopies(groupingElements.size(), Boolean.valueOf(OrderBy.ASC));
-        }
-    }
+    public void setOrderBy(List<OrderByItem> orderBy) {
+		this.orderBy = orderBy;
+	}
     
     public void setOutputMapping(SymbolMap outputMapping) {
 		this.outputMapping = outputMapping;
@@ -150,20 +168,28 @@
 		}
 		
         // Incoming elements and lookup map for evaluating expressions
-        List sourceElements = this.getChildren()[0].getElements();
+        List<SingleElementSymbol> sourceElements = this.getChildren()[0].getElements();
         this.elementMap = createLookupMap(sourceElements);
 
     	// List should contain all grouping columns / expressions as we need those for sorting
-        if(this.sortElements != null) {
-            this.collectedExpressions = new ArrayList<Expression>(this.sortElements.size() + getElements().size());
-            this.collectedExpressions.addAll(sortElements);
+        if(this.orderBy != null) {
+            this.collectedExpressions = new ArrayList<Expression>(this.orderBy.size() + getElements().size());
+            for (OrderByItem item : this.orderBy) {
+            	Expression ex = SymbolMap.getExpression(item.getSymbol());
+                this.collectedExpressions.add(ex);
+			}
+            if (removeDuplicates) {
+            	for (SingleElementSymbol ses : sourceElements) {
+            		collectExpression(SymbolMap.getExpression(ses));
+            	}
+            	distinctCols = collectedExpressions.size();
+            }
         } else {
             this.collectedExpressions = new ArrayList<Expression>(getElements().size());
         }
         
         // Construct aggregate function state accumulators
         functions = new AggregateFunction[getElements().size()];
-        conditions = new int[getElements().size()];
         for(int i=0; i<getElements().size(); i++) {
             Expression symbol = (Expression) getElements().get(i);
             if (this.outputMapping != null) {
@@ -171,12 +197,8 @@
             }
             Class<?> outputType = symbol.getType();
             Class<?> inputType = symbol.getType();
-            conditions[i] = -1;
             if(symbol instanceof AggregateSymbol) {
                 AggregateSymbol aggSymbol = (AggregateSymbol) symbol;
-                if (aggSymbol.getCondition() != null) {
-                	conditions[i] = collectExpression(aggSymbol.getCondition());
-                }
                 if(aggSymbol.getExpression() == null) {
                     functions[i] = new Count();
                 } else {
@@ -244,6 +266,9 @@
                 	}
                     functions[i].setExpressionIndex(index);
                 }
+            	if (aggSymbol.getCondition() != null) {
+                	functions[i].setConditionIndex(collectExpression(aggSymbol.getCondition()));
+                }
             } else {
                 functions[i] = new ConstantFunction();
                 functions[i].setExpressionIndex(this.collectedExpressions.indexOf(symbol));
@@ -288,42 +313,39 @@
     }
 	
 	public TupleSource getCollectionTupleSource() {
-		
 		final RelationalNode sourceNode = this.getChildren()[0];
-		
-		return new BatchCollector.BatchProducerTupleSource(sourceNode) {
-			
-			@Override
-			protected List updateTuple(List tuple) throws ExpressionEvaluationException, BlockedException, TeiidComponentException {
-				int columns = collectedExpressions.size();
-	            List<Object> exprTuple = new ArrayList<Object>(columns);
-	            for(int col = 0; col<columns; col++) { 
-	                // The following call may throw BlockedException, but all state to this point
-	                // is saved in class variables so we can start over on building this tuple
-	                Object value = eval.evaluate(collectedExpressions.get(col), tuple);
-	                exprTuple.add(value);
-	            }
-	            return exprTuple;
-			}
-		};
-		
+		return new ProjectingTupleSource(sourceNode, eval, collectedExpressions);
 	}
 
     private void collectionPhase() {
     	eval = new Evaluator(elementMap, getDataManager(), getContext());
-        if(this.sortElements == null) {
+        if(this.orderBy == null) {
             // No need to sort
             this.groupTupleSource = getCollectionTupleSource();
             this.phase = GROUP;
         } else {
-        	//create a temporary positional schema
-        	List<ElementSymbol> schema = new ArrayList<ElementSymbol>();
-        	for (int i = 0; i < collectedExpressions.size(); i++) {
-        		schema.add(new ElementSymbol(String.valueOf(i)));
+        	List<NullOrdering> nullOrdering = new ArrayList<NullOrdering>(orderBy.size());
+        	List<Boolean> sortTypes = new ArrayList<Boolean>(orderBy.size());
+        	int size = orderBy.size();
+        	if (this.removeDuplicates) {
+        		//sort on all inputs
+        		size = distinctCols;
         	}
-            this.sortUtility = new SortUtility(getCollectionTupleSource(), schema.subList(0, sortElements.size()),
-                                                sortTypes, removeDuplicates?Mode.DUP_REMOVE_SORT:Mode.SORT, getBufferManager(),
-                                                getConnectionID(), schema);
+        	int[] sortIndexes = new int[size];
+        	for (int i = 0; i < size; i++) {
+        		if (i < this.orderBy.size()) {
+        			OrderByItem item = this.orderBy.get(i);
+        			nullOrdering.add(item.getNullOrdering());
+        			sortTypes.add(item.isAscending());
+        		} else {
+        			nullOrdering.add(null);
+        			sortTypes.add(OrderBy.ASC);
+        		}
+        		sortIndexes[i] = i; 
+        	}
+        	this.indexes = Arrays.copyOf(sortIndexes, orderBy.size());
+            this.sortUtility = new SortUtility(getCollectionTupleSource(), removeDuplicates?Mode.DUP_REMOVE_SORT:Mode.SORT, getBufferManager(),
+                    getConnectionID(), collectedExpressions, sortTypes, nullOrdering, sortIndexes);
             this.phase = SORT;
         }
     }
@@ -349,7 +371,7 @@
                 // First row we've seen
                 lastRow = currentGroupTuple;
 
-            } else if(! sameGroup(currentGroupTuple, lastRow)) {
+            } else if(! sameGroup(indexes, currentGroupTuple, lastRow)) {
                 // Close old group
                 List<Object> row = new ArrayList<Object>(functions.length);
                 for(int i=0; i<functions.length; i++) {
@@ -371,7 +393,7 @@
             updateAggregates(currentGroupTuple);
             currentGroupTuple = null;
         }
-        if(lastRow != null || sortElements == null) {
+        if(lastRow != null || orderBy == null) {
             // Close last group
             List<Object> row = new ArrayList<Object>(functions.length);
             for(int i=0; i<functions.length; i++) {
@@ -385,17 +407,14 @@
         return pullBatch();
     }
 
-    private boolean sameGroup(List newTuple, List oldTuple) {
-        // Check for no grouping columns
-        if(sortElements == null) {
-            return true;
-        }
+	public static boolean sameGroup(int[] indexes, List<?> newTuple, List<?> oldTuple) {
+		if (indexes == null) {
+			return true;
+		}
+		for(int i=indexes.length-1; i>=0; i--) {
+            Object oldValue = oldTuple.get(indexes[i]);
+            Object newValue = newTuple.get(indexes[i]);
 
-        // Walk backwards through sort cols as the last columns are most likely to be different
-        for(int i=sortElements.size()-1; i>=0; i--) {
-            Object oldValue = oldTuple.get(i);
-            Object newValue = newTuple.get(i);
-
             if(oldValue == null) {
                 if(newValue != null) {
                     return false;
@@ -417,9 +436,6 @@
     throws TeiidComponentException, TeiidProcessingException {
 
         for(int i=0; i<functions.length; i++) {
-        	if (conditions[i] != -1 && !Boolean.TRUE.equals(tuple.get(conditions[i]))) {
-    			continue;
-        	}
             functions[i].addInput(tuple);
         }
     }
@@ -433,7 +449,7 @@
 
 	protected void getNodeString(StringBuffer str) {
 		super.getNodeString(str);
-		str.append(sortElements);
+		str.append(orderBy);
 		if (outputMapping != null) {
 			str.append(outputMapping);
 		}
@@ -442,10 +458,9 @@
 	public Object clone(){
 		GroupingNode clonedNode = new GroupingNode(super.getID());
 		super.copy(this, clonedNode);
-		clonedNode.sortElements = sortElements;
-		clonedNode.sortTypes = sortTypes;
 		clonedNode.removeDuplicates = removeDuplicates;
 		clonedNode.outputMapping = outputMapping;
+		clonedNode.orderBy = orderBy;
 		return clonedNode;
 	}
 
@@ -453,15 +468,14 @@
         // Default implementation - should be overridden
     	PlanNode props = super.getDescriptionProperties();
 
-        if(sortElements != null) {
-            int elements = sortElements.size();
+        if(orderBy != null) {
+            int elements = orderBy.size();
             List<String> groupCols = new ArrayList<String>(elements);
             for(int i=0; i<elements; i++) {
-                groupCols.add(this.sortElements.get(i).toString());
+                groupCols.add(this.orderBy.get(i).toString());
             }
             props.addProperty(PROP_GROUP_COLS, groupCols);
         }
-        
         props.addProperty(PROP_SORT_MODE, String.valueOf(this.removeDuplicates));
 
         return props;

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/ProjectNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/ProjectNode.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/ProjectNode.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -22,7 +22,7 @@
 
 package org.teiid.query.processor.relational;
 
-import static org.teiid.query.analysis.AnalysisRecord.PROP_SELECT_COLS;
+import static org.teiid.query.analysis.AnalysisRecord.*;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -37,26 +37,24 @@
 import org.teiid.common.buffer.TupleBatch;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
-import org.teiid.core.util.Assertion;
-import org.teiid.query.QueryPlugin;
 import org.teiid.query.analysis.AnalysisRecord;
 import org.teiid.query.processor.ProcessorDataManager;
-import org.teiid.query.sql.symbol.AggregateSymbol;
 import org.teiid.query.sql.symbol.AliasSymbol;
-import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
-import org.teiid.query.sql.symbol.ExpressionSymbol;
-import org.teiid.query.sql.symbol.SelectSymbol;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.util.SymbolMap;
 import org.teiid.query.util.CommandContext;
 
 
 public class ProjectNode extends SubqueryAwareRelationalNode {
 
-	private List selectSymbols;
+	private List<? extends SingleElementSymbol> selectSymbols;
 
     // Derived element lookup map
     private Map elementMap;
     private boolean needsProject = true;
+    private List<Expression> expressions;
+    private int[] projectionIndexes;
 
     // Saved state when blocked on evaluating a row - must be reset
     private TupleBatch currentBatch;
@@ -81,11 +79,11 @@
      * return List of select symbols
      * @return List of select symbols
      */
-    public List getSelectSymbols() {
+    public List<? extends SingleElementSymbol> getSelectSymbols() {
         return this.selectSymbols;
     }
 
-	public void setSelectSymbols(List symbols) {
+	public void setSelectSymbols(List<? extends SingleElementSymbol> symbols) {
 		this.selectSymbols = symbols;
 	}
 	
@@ -95,56 +93,51 @@
 		super.initialize(context, bufferManager, dataMgr);
 
         // Do this lazily as the node may be reset and re-used and this info doesn't change
-        if(elementMap == null) {
-            //in the case of select with no from, there is no child node
-            //simply return at this point
-            if(this.getChildren()[0] == null){
-                elementMap = new HashMap();
-                return;
-            }
+        if(elementMap != null) {
+        	return;
+        }
+    	this.projectionIndexes = new int[this.selectSymbols.size()];
+    	Arrays.fill(this.projectionIndexes, -1);
+    	
+    	this.expressions = new ArrayList<Expression>(this.selectSymbols.size());
+    	for (SingleElementSymbol ses : this.selectSymbols) {
+			this.expressions.add(SymbolMap.getExpression(ses));
+		}
+        //in the case of select with no from, there is no child node
+        //simply return at this point
+        if(this.getChildren()[0] == null){
+            elementMap = new HashMap();
+            return;
+        }
 
-            // Create element lookup map for evaluating project expressions
-            List childElements = this.getChildren()[0].getElements();
-            this.elementMap = createLookupMap(childElements);
+        // Create element lookup map for evaluating project expressions
+        List childElements = this.getChildren()[0].getElements();
+        this.elementMap = createLookupMap(childElements);
 
-            // Check whether project needed at all - this occurs if:
-            // 1. outputMap == null (see previous block)
-            // 2. project elements are either elements or aggregate symbols (no processing required)
-            // 3. order of input values == order of output values
-            if(childElements.size() > 0) {
-                // Start by assuming project is not needed
-                needsProject = false;
-                
-                if(childElements.size() != getElements().size()) {
-                    needsProject = true;                    
-                } else {
-                    for(int i=0; i<selectSymbols.size(); i++) {
-                        SelectSymbol symbol = (SelectSymbol) selectSymbols.get(i);
-                        
-                        if(symbol instanceof AliasSymbol) {
-                            Integer index = (Integer) elementMap.get(symbol);
-                            if(index != null && index.intValue() == i) {
-                                continue;
-                            }
-                            symbol = ((AliasSymbol)symbol).getSymbol();
-                        }
-    
-                        if(symbol instanceof ElementSymbol || symbol instanceof AggregateSymbol) {
-                            Integer index = (Integer) elementMap.get(symbol);
-                            if(index == null || index.intValue() != i) {
-                                // input / output element order is not the same
-                                needsProject = true;
-                                break;
-                            }
-    
-                        } else {
-                            // project element is either a constant or a function
-                            needsProject = true;
-                            break;
-                        }
-                    }
+        // Check whether project needed at all - this occurs if:
+        // 1. outputMap == null (see previous block)
+        // 2. project elements are either elements or aggregate symbols (no processing required)
+        // 3. order of input values == order of output values
+        needsProject = childElements.size() != getElements().size();
+        for(int i=0; i<selectSymbols.size(); i++) {
+            SingleElementSymbol symbol = selectSymbols.get(i);
+            
+            if(symbol instanceof AliasSymbol) {
+                Integer index = (Integer) elementMap.get(symbol);
+                if(index != null && index.intValue() == i) {
+                	projectionIndexes[i] = index;
+                    continue;
                 }
+                symbol = ((AliasSymbol)symbol).getSymbol();
             }
+
+            Integer index = (Integer) elementMap.get(symbol);
+            if(index == null || index.intValue() != i) {
+                // input / output element order is not the same
+                needsProject = true;
+            } else {
+            	projectionIndexes[i] = index;
+            }
         }
     }
 	
@@ -171,14 +164,14 @@
         }
 
         while (currentRow <= currentBatch.getEndRow() && !isBatchFull()) {
-    		List tuple = currentBatch.getTuple(currentRow);
+    		List<?> tuple = currentBatch.getTuple(currentRow);
 
-			List projectedTuple = new ArrayList(selectSymbols.size());
+			List<Object> projectedTuple = new ArrayList<Object>(selectSymbols.size());
 
 			// Walk through symbols
-            for(int i=0; i<selectSymbols.size(); i++) {
-				SelectSymbol symbol = (SelectSymbol) selectSymbols.get(i);
-				updateTuple(symbol, tuple, projectedTuple);
+            for(int i=0; i<expressions.size(); i++) {
+				Expression symbol = expressions.get(i);
+				updateTuple(symbol, i, tuple, projectedTuple);
 			}
 
             // Add to batch
@@ -196,28 +189,14 @@
     	return pullBatch();
 	}
 
-	private void updateTuple(SelectSymbol symbol, List values, List tuple)
+	private void updateTuple(Expression symbol, int projectionIndex, List<?> values, List<Object> tuple)
 		throws BlockedException, TeiidComponentException, ExpressionEvaluationException {
 
-        if (symbol instanceof AliasSymbol) {
-            // First check AliasSymbol itself
-            Integer index = (Integer) elementMap.get(symbol);
-            if(index != null) {
-                tuple.add(values.get(index.intValue()));
-                return;
-            }   
-            // Didn't find it, so try aliased symbol below
-            symbol = ((AliasSymbol)symbol).getSymbol();
-        }
-        
-        Integer index = (Integer) elementMap.get(symbol);
-        if(index != null) {
-			tuple.add(values.get(index.intValue()));
-        } else if(symbol instanceof ExpressionSymbol) {
-            Expression expression = ((ExpressionSymbol)symbol).getExpression();
-			tuple.add(getEvaluator(this.elementMap).evaluate(expression, values));
-        } else {
-            Assertion.failed(QueryPlugin.Util.getString("ERR.015.006.0034", symbol.getClass().getName())); //$NON-NLS-1$
+        int index = this.projectionIndexes[projectionIndex];
+        if(index != -1) {
+			tuple.add(values.get(index));
+        } else { 
+			tuple.add(getEvaluator(this.elementMap).evaluate(symbol, values));
 		}
 	}
 

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/SortUtility.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/SortUtility.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/SortUtility.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -109,19 +109,12 @@
 	private Collection<List<?>> workingTuples;
     
     public SortUtility(TupleSource sourceID, List<OrderByItem> items, Mode mode, BufferManager bufferMgr,
-                        String groupName, List schema) {
-        this.source = sourceID;
-        this.mode = mode;
-        this.bufferManager = bufferMgr;
-        this.groupName = groupName;
-        this.schema = schema;
-        this.schemaSize = bufferManager.getSchemaSize(this.schema);
-        int distinctIndex = items != null? items.size() - 1:0;
+                        String groupName, List<? extends Expression> schema) {
         List<Expression> sortElements = null;
         List<Boolean> sortTypes = null;
         List<NullOrdering> nullOrderings = null;
         if (items == null) {
-    		sortElements = (List<Expression>) this.schema;
+    		sortElements = (List<Expression>) schema;
     		sortTypes = Collections.nCopies(sortElements.size(), OrderBy.ASC);
         } else {
         	sortElements = new ArrayList(items.size());
@@ -148,7 +141,29 @@
             cols[iter.previousIndex()] = schema.indexOf(elem);
             Assertion.assertTrue(cols[iter.previousIndex()] != -1);
         }
+        init(sourceID, mode, bufferMgr, groupName, schema, sortTypes,
+				nullOrderings, cols);
+    }
+    
+    public SortUtility(TupleSource sourceID, Mode mode, BufferManager bufferMgr,
+			String groupName, List<? extends Expression> schema,
+			List<Boolean> sortTypes, List<NullOrdering> nullOrderings,
+			int[] cols) {
+    	init(sourceID, mode, bufferMgr, groupName, schema, sortTypes, nullOrderings, cols);
+    }
+
+	private void init(TupleSource sourceID, Mode mode, BufferManager bufferMgr,
+			String groupName, List<? extends Expression> schema,
+			List<Boolean> sortTypes, List<NullOrdering> nullOrderings,
+			int[] cols) {
+		this.source = sourceID;
+        this.mode = mode;
+        this.bufferManager = bufferMgr;
+        this.groupName = groupName;
+        this.schema = schema;
+        this.schemaSize = bufferManager.getSchemaSize(this.schema);
         this.comparator = new ListNestedSortComparator(cols, sortTypes);
+        int distinctIndex = cols.length - 1;
         this.comparator.setDistinctIndex(distinctIndex);
         this.comparator.setNullOrdering(nullOrderings);
     }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -158,4 +158,9 @@
         // Return
         return this.proxy.getResult();
     }
+    
+    @Override
+    public boolean respectsNull() {
+    	return this.proxy.respectsNull();
+    }
 }

Added: trunk/engine/src/main/java/org/teiid/query/processor/relational/WindowFunctionProjectNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/WindowFunctionProjectNode.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/WindowFunctionProjectNode.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -0,0 +1,497 @@
+/*
+ * 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.processor.relational;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.teiid.api.exception.query.ExpressionEvaluationException;
+import org.teiid.api.exception.query.FunctionExecutionException;
+import org.teiid.common.buffer.BlockedException;
+import org.teiid.common.buffer.BufferManager;
+import org.teiid.common.buffer.IndexedTupleSource;
+import org.teiid.common.buffer.STree;
+import org.teiid.common.buffer.TupleBatch;
+import org.teiid.common.buffer.TupleBuffer;
+import org.teiid.common.buffer.TupleSource;
+import org.teiid.common.buffer.BufferManager.TupleSourceType;
+import org.teiid.common.buffer.STree.InsertMode;
+import org.teiid.core.TeiidComponentException;
+import org.teiid.core.TeiidProcessingException;
+import org.teiid.core.types.DataTypeManager;
+import org.teiid.language.SortSpecification.NullOrdering;
+import org.teiid.query.eval.Evaluator;
+import org.teiid.query.function.aggregate.AggregateFunction;
+import org.teiid.query.function.aggregate.ArrayAgg;
+import org.teiid.query.function.aggregate.Avg;
+import org.teiid.query.function.aggregate.Count;
+import org.teiid.query.function.aggregate.Max;
+import org.teiid.query.function.aggregate.Min;
+import org.teiid.query.function.aggregate.RankingFunction;
+import org.teiid.query.function.aggregate.StatsFunction;
+import org.teiid.query.function.aggregate.Sum;
+import org.teiid.query.function.aggregate.TextAgg;
+import org.teiid.query.function.aggregate.XMLAgg;
+import org.teiid.query.processor.ProcessorDataManager;
+import org.teiid.query.processor.relational.GroupingNode.ProjectingTupleSource;
+import org.teiid.query.processor.relational.SortUtility.Mode;
+import org.teiid.query.sql.lang.OrderBy;
+import org.teiid.query.sql.lang.OrderByItem;
+import org.teiid.query.sql.symbol.AggregateSymbol;
+import org.teiid.query.sql.symbol.ElementSymbol;
+import org.teiid.query.sql.symbol.Expression;
+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.AggregateSymbol.Type;
+import org.teiid.query.sql.util.SymbolMap;
+import org.teiid.query.util.CommandContext;
+
+
+public class WindowFunctionProjectNode extends SubqueryAwareRelationalNode {
+	
+	private enum Phase {
+		COLLECT,
+		PROCESS,
+		OUTPUT
+	}
+	
+	private static class WindowFunctionInfo {
+		WindowFunction function;
+		int expressionIndex = -1;
+		int conditionIndex = -1;
+		int outputIndex;
+	}
+	
+	private static class WindowSpecificationInfo {
+		List<Integer> groupIndexes = new ArrayList<Integer>();
+		List<Integer> sortIndexes = new ArrayList<Integer>();
+		List<NullOrdering> nullOrderings = new ArrayList<NullOrdering>();
+		List<Boolean> orderType = new ArrayList<Boolean>();
+		List<WindowFunctionInfo> functions = new ArrayList<WindowFunctionInfo>();
+	}
+	
+	private LinkedHashMap<WindowSpecification, WindowSpecificationInfo> windows = new LinkedHashMap<WindowSpecification, WindowSpecificationInfo>();
+	private LinkedHashMap<Expression, Integer> expressionIndexes;
+	private LinkedHashMap<Integer, Integer> passThrough = new LinkedHashMap<Integer, Integer>();
+	
+	private Map elementMap;
+	
+	//processing state
+	private Phase phase = Phase.COLLECT;
+	private TupleBuffer tb;
+	private TupleSource inputTs;
+	private STree[] partitionMapping;
+	private STree[] valueMapping;
+	private IndexedTupleSource outputTs;
+	
+	public WindowFunctionProjectNode(int nodeId) {
+		super(nodeId);
+	}
+	
+	protected WindowFunctionProjectNode() {
+	}
+	
+	@Override
+	public void reset() {
+		super.reset();
+		this.tb = null;
+		this.inputTs = null;
+		this.phase = Phase.COLLECT;
+		this.partitionMapping = null;
+		this.valueMapping = null;
+		this.outputTs = null;
+	}
+	
+	@Override
+	public void closeDirect() {
+		if (tb != null) {
+			tb.remove();
+			tb = null;
+		}
+		if (partitionMapping != null) {
+			for (STree tree : partitionMapping) {
+				if (tree != null) {
+					tree.remove();
+				}
+			}
+			partitionMapping = null;
+		}
+		if (valueMapping != null) {
+			for (STree tree : valueMapping) {
+				tree.remove();
+			}
+			valueMapping = null;
+		}
+	}
+	
+	public Object clone(){
+		WindowFunctionProjectNode clonedNode = new WindowFunctionProjectNode();
+        this.copy(this, clonedNode);
+        clonedNode.windows = windows;
+        clonedNode.expressionIndexes = expressionIndexes;
+        clonedNode.passThrough = passThrough;
+		return clonedNode;
+	}
+	
+	/**
+	 * This state can be determined prior to initialize and is the same for all nodes,
+	 * so it is moved into it's own init routine
+	 */
+	public void init() {
+		expressionIndexes = new LinkedHashMap<Expression, Integer>();
+		for (int i = 0; i < getElements().size(); i++) {
+			Expression ex = SymbolMap.getExpression((Expression) getElements().get(i));
+			if (ex instanceof WindowFunction) {
+				WindowFunction wf = (WindowFunction)ex;
+				WindowSpecification ws = wf.getWindowSpecification();
+				WindowSpecificationInfo wsi = windows.get(ws);
+				if (wsi == null) {
+					wsi = new WindowSpecificationInfo();
+					windows.put(wf.getWindowSpecification(), wsi);
+					if (ws.getPartition() != null) {
+						for (Expression ex1 : ws.getPartition()) {
+							Integer index = getIndex(ex1);
+							wsi.groupIndexes.add(index);
+							wsi.orderType.add(OrderBy.ASC);
+							wsi.nullOrderings.add(null);
+						}
+					}
+					if (ws.getOrderBy() != null) {
+						for (OrderByItem item : ws.getOrderBy().getOrderByItems()) {
+							Expression ex1 = SymbolMap.getExpression(item.getSymbol());
+							Integer index = getIndex(ex1);
+							wsi.sortIndexes.add(index);
+							wsi.orderType.add(item.isAscending());
+							wsi.nullOrderings.add(item.getNullOrdering());
+						}
+					}
+				}
+				WindowFunctionInfo wfi = new WindowFunctionInfo();
+				wfi.function = wf;
+				ex = wf.getFunction().getExpression();
+				if (ex != null) {
+					wfi.expressionIndex = getIndex(ex);
+				}
+				if (wf.getFunction().getCondition() != null) {
+					ex = wf.getFunction().getCondition();
+					wfi.conditionIndex = getIndex(ex);
+				}
+				wfi.outputIndex = i;
+				wsi.functions.add(wfi);
+			} else {
+				int index = getIndex(ex);
+				passThrough.put(i, index);
+			}
+		}
+	}
+
+	@Override
+	protected TupleBatch nextBatchDirect() throws BlockedException,
+			TeiidComponentException, TeiidProcessingException {
+		
+		if (phase == Phase.COLLECT) {
+			saveInput();
+			phase = Phase.PROCESS;
+			partitionMapping = new STree[this.windows.size()];
+			valueMapping = new STree[this.windows.size()];
+		}
+		
+		if (phase == Phase.PROCESS) {
+			buildResults();
+			phase = Phase.OUTPUT;
+		}
+		
+		if (phase == Phase.OUTPUT) {
+			if (outputTs == null) {
+				outputTs = tb.createIndexedTupleSource(true);
+			}
+			while (outputTs.hasNext()) {
+				List<?> tuple = outputTs.nextTuple();
+				int rowId = (Integer)tuple.get(tuple.size() - 1);
+				int size = getElements().size();
+				ArrayList<Object> outputRow = new ArrayList<Object>(size);
+				for (int i = 0; i < size; i++) {
+					outputRow.add(null);
+				}
+				for (Map.Entry<Integer, Integer> entry : passThrough.entrySet()) {
+					outputRow.set(entry.getKey(), tuple.get(entry.getValue()));
+				}
+				List<Map.Entry<WindowSpecification, WindowSpecificationInfo>> specs = new ArrayList<Map.Entry<WindowSpecification,WindowSpecificationInfo>>(windows.entrySet());
+				for (int specIndex = 0; specIndex < specs.size(); specIndex++) {
+					Map.Entry<WindowSpecification, WindowSpecificationInfo> entry = specs.get(specIndex);
+					List<?> idRow = Arrays.asList(rowId);
+					if (partitionMapping[specIndex] != null) {
+						idRow = partitionMapping[specIndex].find(idRow);
+						idRow = idRow.subList(1, 2);
+					}
+					List<?> valueRow = valueMapping[specIndex].find(idRow);
+					List<WindowFunctionInfo> functions = entry.getValue().functions;
+					for (int i = 0; i < functions.size(); i++) {
+						WindowFunctionInfo wfi = functions.get(i);
+						outputRow.set(wfi.outputIndex, valueRow.get(i+1));
+					}
+				}
+				this.addBatchRow(outputRow);
+				if (this.isBatchFull()) {
+					return pullBatch();
+				}
+			}
+			terminateBatches();
+		}
+		return this.pullBatch();
+	}
+
+	/**
+	 * Build the results by maintaining indexes that either map
+	 * rowid->values
+	 * or
+	 * rowid->partitionid and partitionid->values
+	 * 
+	 * TODO use the size hint for tree balancing
+	 */
+	private void buildResults() throws TeiidComponentException,
+			TeiidProcessingException, FunctionExecutionException,
+			ExpressionEvaluationException {
+		List<Map.Entry<WindowSpecification, WindowSpecificationInfo>> specs = new ArrayList<Map.Entry<WindowSpecification,WindowSpecificationInfo>>(windows.entrySet());
+		for (int specIndex = 0; specIndex < specs.size(); specIndex++) {
+			Map.Entry<WindowSpecification, WindowSpecificationInfo> entry = specs.get(specIndex);
+			WindowSpecificationInfo info = entry.getValue();
+			IndexedTupleSource specificationTs = tb.createIndexedTupleSource();
+			int[] groupingIndexes = null;
+			int[] orderIndexes = null;
+
+			//if there is partitioning or ordering, then sort
+			if (!info.orderType.isEmpty()) {
+				int[] sortKeys = new int[info.orderType.size()];
+				int i = 0;
+				if (!info.groupIndexes.isEmpty()) {
+					for (Integer sortIndex : info.groupIndexes) {
+						sortKeys[i++] = sortIndex;
+					}
+					groupingIndexes = Arrays.copyOf(sortKeys, info.groupIndexes.size());
+					ElementSymbol key = new ElementSymbol("rowid"); //$NON-NLS-1$
+					key.setType(DataTypeManager.DefaultDataClasses.INTEGER);
+					ElementSymbol value = new ElementSymbol("partitionid"); //$NON-NLS-1$
+					key.setType(DataTypeManager.DefaultDataClasses.INTEGER);
+					List<ElementSymbol> elements = Arrays.asList(key, value);
+					partitionMapping[specIndex] = this.getBufferManager().createSTree(elements, this.getConnectionID(), 1);
+				}
+				if (!info.sortIndexes.isEmpty()) {
+					for (Integer sortIndex : info.sortIndexes) {
+						sortKeys[i++] = sortIndex;
+					}
+					orderIndexes = Arrays.copyOfRange(sortKeys, info.groupIndexes.size(), info.groupIndexes.size() + info.sortIndexes.size());
+				}
+				SortUtility su = new SortUtility(specificationTs, Mode.SORT, this.getBufferManager(), this.getConnectionID(), tb.getSchema(), info.orderType, info.nullOrderings, sortKeys);
+				TupleBuffer sorted = su.sort();
+				specificationTs = sorted.createIndexedTupleSource(true);
+			}
+			List<AggregateFunction> aggs = initializeAccumulators(info, specIndex, orderIndexes);
+
+			int partitionId = 0;
+			List<?> lastRow = null;
+			while (specificationTs.hasNext()) {
+				List<?> tuple = specificationTs.nextTuple();
+				boolean sameGroup = true;
+				if (lastRow != null) {
+		        	sameGroup = GroupingNode.sameGroup(groupingIndexes, tuple, lastRow);
+		        	if (!sameGroup || orderIndexes != null) {
+		        		saveValues(specIndex, orderIndexes, aggs, partitionId, lastRow, sameGroup);
+		        	}
+				}
+		        if (orderIndexes == null) {
+		        	if (!sameGroup) {
+		        		partitionId++;
+		        	}
+		        	List<Object> partitionTuple = Arrays.asList(tuple.get(tuple.size() - 1), partitionId);
+					partitionMapping[specIndex].insert(partitionTuple, InsertMode.NEW, -1);
+		        }
+		        for (AggregateFunction function : aggs) {
+		        	function.addInput(tuple);
+		        }
+		        lastRow = tuple;
+			}
+		    if(lastRow != null) {
+		    	saveValues(specIndex, orderIndexes, aggs, partitionId, lastRow, true);
+		    }
+		}
+	}
+
+	private void saveValues(int specIndex, int[] orderIndexes,
+			List<AggregateFunction> aggs, int partitionId, List<?> tuple,
+			boolean sameGroup) throws FunctionExecutionException,
+			ExpressionEvaluationException, TeiidComponentException,
+			TeiidProcessingException {
+		List<Object> row = new ArrayList<Object>(aggs.size() + 1);
+		if (orderIndexes == null) {
+			row.add(partitionId);
+		} else {
+			//use the rowid
+			row.add(tuple.get(tuple.size() - 1));
+		}
+		for (AggregateFunction function : aggs) {
+			row.add(function.getResult());
+			if (!sameGroup) {
+				function.reset();
+			}
+		}
+		valueMapping[specIndex].insert(row, orderIndexes != null?InsertMode.NEW:InsertMode.ORDERED, -1);
+	}
+
+	private List<AggregateFunction> initializeAccumulators(WindowSpecificationInfo info, int specIndex,
+			int[] orderIndexes) {
+		List<AggregateFunction> aggs = new ArrayList<AggregateFunction>();
+		//initialize the function accumulators
+		List<ElementSymbol> elements = new ArrayList<ElementSymbol>(info.functions.size() + 1);
+		ElementSymbol key = new ElementSymbol("id"); //$NON-NLS-1$
+		key.setType(DataTypeManager.DefaultDataClasses.INTEGER);
+		elements.add(key);
+
+		CommandContext context = this.getContext();
+		for (WindowFunctionInfo wfi : info.functions) {
+			AggregateSymbol aggSymbol = wfi.function.getFunction();
+		    Class<?> outputType = aggSymbol.getType();
+		    ElementSymbol value = new ElementSymbol("val"); //$NON-NLS-1$
+		    value.setType(outputType);
+		    elements.add(value);
+		    Class<?> inputType = aggSymbol.getType();
+		    if (aggSymbol.getExpression() != null) {
+		    	inputType = aggSymbol.getExpression().getType();
+		    }
+			Type function = aggSymbol.getAggregateFunction();
+			AggregateFunction af = null;
+			switch (function) {
+			case RANK:
+			case DENSE_RANK:
+				af = new RankingFunction(function, orderIndexes);
+				break;
+			case ROW_NUMBER: //same as count(*)
+			case COUNT:
+				af = new Count();
+				break;
+			case SUM:
+				af = new Sum();
+				break;
+			case AVG:
+				af = new Avg();
+				break;
+			case MIN:
+				af = new Min();
+				break;
+			case MAX:
+				af = new Max();
+				break;
+			case XMLAGG:
+				af = new XMLAgg(context);
+				break;
+			case ARRAY_AGG:
+				af = new ArrayAgg(context);
+				break;                		
+			case TEXTAGG:
+				af = new TextAgg(context, (TextLine)aggSymbol.getExpression());
+				break;                		
+			default:
+				af = new StatsFunction(function);
+			}
+
+			af.setExpressionIndex(wfi.expressionIndex);
+			af.setConditionIndex(wfi.conditionIndex);
+			af.initialize(outputType, inputType);
+			aggs.add(af);
+		}
+		
+		valueMapping[specIndex] = this.getBufferManager().createSTree(elements, this.getConnectionID(), 1);
+
+		return aggs;
+	}
+
+	/**
+	 * Save the input generating any necessary expressions and adding a row id
+	 * @param collectedExpressions
+	 * @return
+	 * @throws TeiidComponentException
+	 * @throws TeiidProcessingException
+	 */
+	private void saveInput()
+			throws TeiidComponentException, TeiidProcessingException {
+		if (inputTs == null) {
+			List<Expression> collectedExpressions = new ArrayList<Expression>(expressionIndexes.keySet());
+			Evaluator eval = new Evaluator(elementMap, getDataManager(), getContext());
+			final RelationalNode sourceNode = this.getChildren()[0];
+			inputTs = new ProjectingTupleSource(sourceNode, eval, collectedExpressions) {
+				int index = 0;
+				@Override
+				public List<Object> nextTuple() throws TeiidComponentException,
+						TeiidProcessingException {
+					List<Object> tuple = super.nextTuple();
+					if (tuple != null) {
+						tuple.add(index++);
+					}
+					return tuple;
+				}
+			};
+			List<ElementSymbol> schema = new ArrayList<ElementSymbol>(collectedExpressions.size() + 1);
+			int index = 0;
+			for (Expression ex : collectedExpressions) {
+				ElementSymbol es = new ElementSymbol(String.valueOf(index++));
+				es.setType(ex.getType());
+				schema.add(es);
+			}
+			//add in the row id
+			ElementSymbol es = new ElementSymbol(String.valueOf(index++));
+			es.setType(DataTypeManager.DefaultDataClasses.INTEGER);
+			schema.add(es);
+			tb = this.getBufferManager().createTupleBuffer(schema, this.getConnectionID(), TupleSourceType.PROCESSOR);
+		}
+		
+		List<?> tuple = null;
+		while ((tuple = inputTs.nextTuple()) != null) {
+			tb.addTuple(tuple);
+		}
+		tb.close();
+		inputTs.closeSource();
+		inputTs = null;
+	}
+
+	private Integer getIndex(Expression ex) {
+		Integer index = expressionIndexes.get(ex);
+		if (index == null) {
+			index = expressionIndexes.size();
+			expressionIndexes.put(ex, index);
+		}
+		return index;
+	}
+	
+	@Override
+	public void initialize(CommandContext context, BufferManager bufferManager,
+			ProcessorDataManager dataMgr) {
+		super.initialize(context, bufferManager, dataMgr);
+		List sourceElements = this.getChildren()[0].getElements();
+        this.elementMap = createLookupMap(sourceElements);
+	}
+    
+}


Property changes on: trunk/engine/src/main/java/org/teiid/query/processor/relational/WindowFunctionProjectNode.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/XMLTableNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/XMLTableNode.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/XMLTableNode.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -266,9 +266,6 @@
 	public void processRow(NodeInfo row) {
 		this.item = row;
 		rowCount++;
-		if (rowCount % 100 == 0) {
-			System.out.println(System.currentTimeMillis() + " " + rowCount);
-		}
 		try {
 			this.buffer.addTuple(processRow());
 		} catch (TeiidException e) {

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -163,25 +163,30 @@
 	 * @return Type of the symbol
 	 */
 	public Class<?> getType() {
-		if(this.aggregate == Type.COUNT) {
+		switch (this.aggregate) {
+		case COUNT:
 			return COUNT_TYPE;
-		} else if(this.aggregate == Type.SUM ) {
+		case SUM:
 			Class<?> expressionType = this.getExpression().getType();
 			return SUM_TYPES.get(expressionType);
-        } else if (this.aggregate == Type.AVG) {
-            Class<?> expressionType = this.getExpression().getType();
+		case AVG:
+            expressionType = this.getExpression().getType();
             return AVG_TYPES.get(expressionType);
-		} else if (isBoolean()) {
+		case ARRAY_AGG:
+			return DataTypeManager.DefaultDataClasses.OBJECT;
+		case TEXTAGG:
+			return DataTypeManager.DefaultDataClasses.BLOB;
+		case RANK:
+		case ROW_NUMBER:
+		case DENSE_RANK:
+			return DataTypeManager.DefaultDataClasses.INTEGER;
+		}
+		if (isBoolean()) {
 			return DataTypeManager.DefaultDataClasses.BOOLEAN;
 		} else if (isEnhancedNumeric()) {
 			return DataTypeManager.DefaultDataClasses.DOUBLE;
-		} else if (this.aggregate == Type.ARRAY_AGG) {
-			return DataTypeManager.DefaultDataClasses.OBJECT;
-		} else if (this.aggregate == Type.RANK || this.aggregate == Type.ROW_NUMBER || this.aggregate == Type.DENSE_RANK){
-			return DataTypeManager.DefaultDataClasses.INTEGER;
-		} else {
-			return this.getExpression().getType();
 		}
+		return this.getExpression().getType();
 	}
 
 	public boolean isBoolean() {

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -88,7 +88,7 @@
 	
 	@Override
 	public Class<?> getType() {
-		return DataTypeManager.DefaultDataClasses.BLOB;
+		return DataTypeManager.DefaultDataClasses.STRING;
 	}
 
 	@Override

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/WindowFunction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/WindowFunction.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/WindowFunction.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -27,15 +27,19 @@
 import org.teiid.query.sql.LanguageVisitor;
 import org.teiid.query.sql.visitor.SQLStringVisitor;
 
-public class WindowFunction implements Expression {
+public class WindowFunction extends SingleElementSymbol {
 	
 	private AggregateSymbol function;
 	private WindowSpecification windowSpecification;
 	
-	public WindowFunction() {
-		
+	public WindowFunction(String name) {
+		super(name);
 	}
 	
+	protected WindowFunction(String name, String canonical) {
+		super(name, canonical);
+	}
+	
 	public AggregateSymbol getFunction() {
 		return function;
 	}
@@ -88,7 +92,7 @@
 	
 	@Override
 	public WindowFunction clone() {
-		WindowFunction clone = new WindowFunction();
+		WindowFunction clone = new WindowFunction(this.getName(), this.getCanonical());
 		clone.setFunction((AggregateSymbol) this.function.clone());
 		clone.setWindowSpecification(this.windowSpecification.clone());
 		return clone;

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -391,14 +391,26 @@
         }
         final ExpressionMappingVisitor visitor = new ExpressionMappingVisitor(exprMap);
         visitor.elementSymbolsOnly = true;
+        boolean preOrder = true;
+        boolean useReverseMapping = true;
         for (Map.Entry<? extends Expression, ? extends Expression> entry : exprMap.entrySet()) {
         	if (!(entry.getKey() instanceof ElementSymbol)) {
         		visitor.elementSymbolsOnly = false;
         		break;
         	}
 		}
-        boolean useReverseMapping = !Collections.disjoint(GroupsUsedByElementsVisitor.getGroups(exprMap.keySet()),
-        		GroupsUsedByElementsVisitor.getGroups(exprMap.values()));
+        if (!visitor.elementSymbolsOnly) {
+        	for (Map.Entry<? extends Expression, ? extends Expression> entry : exprMap.entrySet()) {
+            	if (!(entry.getValue() instanceof ElementSymbol)) {
+            		useReverseMapping = !Collections.disjoint(GroupsUsedByElementsVisitor.getGroups(exprMap.keySet()),
+                    		GroupsUsedByElementsVisitor.getGroups(exprMap.values()));
+            		break;
+            	}
+    		}
+        } else {
+        	preOrder = false;
+        	useReverseMapping = false;
+        }
         
         if (useReverseMapping) {
 	        final Set<Expression> reverseSet = new HashSet<Expression>(exprMap.values());
@@ -412,7 +424,7 @@
 	        };
 	        obj.acceptVisitor(pon);
         } else {
-        	PreOrPostOrderNavigator.doVisit(obj, visitor, PreOrPostOrderNavigator.PRE_ORDER, false);
+        	PreOrPostOrderNavigator.doVisit(obj, visitor, preOrder, false);
         }
     }
     

Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -756,7 +756,13 @@
         Criteria having = query.getHaving();
         validateNoAggsInClause(groupBy);
         validateNoAggsInClause(query.getCriteria());
-        validateNoAggsInClause(query.getFrom());
+        if (query.getFrom() == null) {
+        	validateNoAggsInClause(select);
+        	validateNoAggsInClause(query.getOrderBy());
+        } else {
+        	validateNoAggsInClause(query.getFrom());
+        }
+        
         Set<Expression> groupSymbols = null;
         boolean hasAgg = false;
         if (groupBy != null) {
@@ -1212,10 +1218,20 @@
     	case DENSE_RANK:
     	case ROW_NUMBER:
     		if (windowFunction.getWindowSpecification().getOrderBy() == null) {
-    			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.analytical_requires_order_by", windowFunction), windowFunction); //$NON-NLS-1$
+    			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.ranking_requires_order_by", windowFunction), windowFunction); //$NON-NLS-1$
     		}
+    		break;
+    	case TEXTAGG:
+    	case ARRAY_AGG:
+    		if (windowFunction.getWindowSpecification().getOrderBy() != null) {
+    			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.window_order_by", windowFunction), windowFunction); //$NON-NLS-1$
+            }
+    		break;
     	}
     	validateNoSubqueriesOrOuterReferences(windowFunction);
+        if (windowFunction.getFunction().getOrderBy() != null || windowFunction.getFunction().isDistinct()) {
+        	handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0042", new Object[] {windowFunction.getFunction(), windowFunction}), windowFunction); //$NON-NLS-1$
+        }
     }
     
     @Override
@@ -1256,9 +1272,6 @@
         		handleValidationError(QueryPlugin.Util.getString("AggregateValidationVisitor.invalid_distinct", new Object[] {aggregateFunction, obj}), obj); //$NON-NLS-1$
         	}
         }
-        if (obj.isWindowed() && obj.getOrderBy() != null) {
-        	handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0042", new Object[] {aggregateFunction, obj}), obj); //$NON-NLS-1$
-        }
     	if (obj.getAggregateFunction() != Type.TEXTAGG) {
     		return;
     	}

Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2011-07-27 14:43:28 UTC (rev 3339)
@@ -1869,17 +1869,11 @@
 	)
 	{		
 		SingleElementSymbol es = null;
-		if(expression instanceof ElementSymbol) {
-			es = (ElementSymbol) expression;
+		if(!(expression instanceof SingleElementSymbol)) {
+			String functionName = generateFunctionName(info, null);
+			es = new ExpressionSymbol(functionName, expression);
 		} else {
-			String func = null;
-			if(expression instanceof AggregateSymbol) {
-		    	es = (AggregateSymbol)expression;
-		    	func = ((AggregateSymbol)expression).getAggregateFunction().name();
-			} else {
-				String functionName = generateFunctionName(info, null);
-				es = new ExpressionSymbol(functionName, expression);
-			}
+		    es = (SingleElementSymbol)expression;
 		}
 		if(alias != null) {
 			alias = validateAlias(alias); 
@@ -3455,7 +3449,10 @@
     [orderBy = orderby(info)]
     <RPAREN>
     {
-    	WindowFunction result = new WindowFunction();
+        String aggName = "win_" + ((AggregateSymbol)agg).getName();
+		String name = generateFunctionName(info, aggName);
+        
+    	WindowFunction result = new WindowFunction(aggName);
     	WindowSpecification ws = new WindowSpecification();
     	result.setFunction((AggregateSymbol)agg);
     	ws.setPartition(partitionList);

Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2011-07-27 14:43:28 UTC (rev 3339)
@@ -207,7 +207,7 @@
 ERR.015.012.0037 = {0} cannot be used outside of aggregate functions since they are not present in a GROUP BY clause.
 ERR.015.012.0039 = Nested aggregate expressions are not allowed: {0}
 ERR.015.012.0041 = The aggregate function {0} cannot be used with non-numeric expressions: {1}
-ERR.015.012.0042 = The aggregate function {0} cannot use its own order by clause when windowed: {1}
+ERR.015.012.0042 = A windowed aggregate function {0} cannot use its own order by clause or be distinct: {1}
 AggregateValidationVisitor.non_comparable = The aggregate function {0} cannot be used with non-comparable expressions: {1}
 AggregateValidationVisitor.non_xml = The XMLAGG aggregate function {0} requires an expression of type XML: {1}
 AggregateValidationVisitor.non_boolean=The boolean aggregate functions ANY, SOME, EVERY require a boolean expression.
@@ -259,7 +259,7 @@
 
 
 SQLParser.Unknown_join_type=Unknown join type: {0}
-SQLParser.Aggregate_only_top_level=Aggregate functions are only allowed HAVING/SELECT/ORDER BY clauses.  Window functions are only allowed in the SELECT/ORDER BY clauses: {0}
+SQLParser.Aggregate_only_top_level=Aggregate functions are only allowed HAVING/SELECT/ORDER BY clauses.  Window functions are only allowed in the SELECT/ORDER BY clauses: {0}.  Both require a FROM clause to be present.
 SQLParser.window_only_top_level=Window functions are not allowed in the HAVING clause: {0}
 SQLParser.Unknown_agg_func=Unknown aggregate function: {0}
 SQLParser.Invalid_func=Invalid function name: [{0}]
@@ -680,7 +680,8 @@
 SimpleQueryResolver.procedure_cache_not_used=Procedure caching will not be used for {0} due to the use of OPTION NOCACHE.
 ValidationVisitor.groupby_subquery=Expressions used in a GROUP BY clause cannot be constant and must not contain subqueries: "{0}".
 ValidationVisitor.filter_subquery=Expressions used in a FILTER clause or a window function must not contain subqueries nor outer references: "{0}".
-ValidationVisitor.analytical_requires_order_by=The window analytical functions RANK, DENSE_RANK, and ROW_NUMBER require the use of an ORDER BY clause in the window specification: {0}.
+ValidationVisitor.ranking_requires_order_by=The window ranking functions RANK, DENSE_RANK, and ROW_NUMBER require the use of an ORDER BY clause in the window specification: {0}.
+ValidationVisitor.window_order_by=The window specification for TEXTAGG and ARRAY_AGG cannot use an ORDER BY clause: {0}.
 ValidationVisitor.Procedure_has_group_self_reference=Procedure cannot have a Group reference to itself.
 ExpressionEvaluator.Expected_props_for_payload_function=Unable to evaluate {0}: expected Properties for command payload but got object of type {1}
 ValidationVisitor.The_rowlimit_function_cannot_be_used_in_a_non-XML_command=The ''rowlimit'' and ''rowlimitexception'' functions cannot be used in a non-XML command

Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -363,6 +363,27 @@
     	assertEquals(1, agds.getExecuteCount().get());
     }
     
+    @Test public void testUsingFinalBuffer() throws Exception {
+    	String sql = "select intkey from bqt1.smalla union select 1";
+    	((BufferManagerImpl)core.getBufferManager()).setProcessorBatchSize(2);
+    	agds.sleep = 500;
+        RequestMessage reqMsg = exampleRequestMessage(sql);
+        Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
+        ResultsMessage rm = message.get(500000, TimeUnit.MILLISECONDS);
+        assertNull(rm.getException());
+        assertEquals(1, rm.getResults().length);
+
+        message = core.processCursorRequest(reqMsg.getExecutionId(), 3, 2);
+        rm = message.get(500000, TimeUnit.MILLISECONDS);
+        assertNull(rm.getException());
+        assertEquals(1, rm.getResults().length);
+        
+        message = core.processCursorRequest(reqMsg.getExecutionId(), 3, 2);
+        rm = message.get(500000, TimeUnit.MILLISECONDS);
+        assertNull(rm.getException());
+        assertEquals(0, rm.getResults().length);
+    }
+    
     @Test public void testPreparedPlanInvalidation() throws Exception {
         String sql = "insert into #temp select * FROM vqt.SmallB"; //$NON-NLS-1$
         String userName = "1"; //$NON-NLS-1$

Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestMetaDataProcessor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestMetaDataProcessor.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestMetaDataProcessor.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -155,7 +155,17 @@
         helpCheckNumericAttributes(response, 2, 22, 20, 0);
         helpCheckNumericAttributes(response, 3, 22, 20, 0);
     }
-    
+
+    @Test public void testWindowFunction() throws Exception {
+        QueryMetadataInterface metadata = TestMetaDataProcessor.examplePrivatePhysicalModel(); 
+        String sql = "SELECT min(e1) over () FROM pm1.g2"; //$NON-NLS-1$
+        
+        MetadataResult response = helpTestQuery(metadata, sql, TestMetaDataProcessor.examplePrivatePhysicalModelVDB());
+        helpCheckNumericAttributes(response, 0, 21, 19, 4);
+        assertEquals("e1", response.getColumnMetadata()[0].get(ResultsMetadataConstants.ELEMENT_NAME)); //$NON-NLS-1$
+        assertEquals("win_min", response.getColumnMetadata()[0].get(ResultsMetadataConstants.ELEMENT_LABEL)); //$NON-NLS-1$
+    }
+
     @Test public void testMetadataGenerationForAllTypes() throws Exception {
         Set<String> dataTypes = DataTypeManager.getAllDataTypeNames();
         for (String type : dataTypes) {
@@ -246,7 +256,7 @@
 	    Table pm1g2 = RealMetadataFactory.createPhysicalGroup("g2", pm1); //$NON-NLS-1$
 	    
 	    // Create physical elements
-	    List<Column> pm1g1e = RealMetadataFactory.createElements(pm1g1, 
+	    RealMetadataFactory.createElements(pm1g1, 
 	        new String[] { "e1"}, //$NON-NLS-1$ 
 	        new String[] { DataTypeManager.DefaultDataTypes.SHORT});
 	

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -146,6 +146,39 @@
         checkNodeTypes(plan, new int[] {0}, new Class[] {DupRemoveSortNode.class});
     }
 
+    /**
+     * The grouping expression inhibits combining the dup removal.
+     */
+    @Test public void testGroupDupCombination1() { 
+        FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+        BasicSourceCapabilities caps = new BasicSourceCapabilities();
+        capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+
+        // Create query 
+        String sql = "select max(e1), e2 || e1 from (select distinct e1, e2 from pm1.g1) x group by e2 || e1"; //$NON-NLS-1$
+
+        ProcessorPlan plan = helpPlan(sql, RealMetadataFactory.example1Cached(), null, capFinder, 
+                                      new String[] {"SELECT pm1.g1.e1, pm1.g1.e2 FROM pm1.g1"}, TestOptimizer.SHOULD_SUCCEED); //$NON-NLS-1$ 
+        
+        checkNodeTypes(plan, new int[] {
+                1,      // Access
+                0,      // DependentAccess
+                0,      // DependentSelect
+                0,      // DependentProject
+                0,      // DupRemove
+                1,      // Grouping
+                0,      // NestedLoopJoinStrategy
+                0,      // MergeJoinStrategy
+                0,      // Null
+                0,      // PlanExecution
+                1,      // Project
+                0,      // Select
+                0,      // Sort
+                0       // UnionAll
+            });
+        checkNodeTypes(plan, new int[] {1}, new Class[] {DupRemoveSortNode.class});
+    }
+
     @Test public void testSortGroupCombination() { 
         FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
         BasicSourceCapabilities caps = new BasicSourceCapabilities();

Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -6849,13 +6849,13 @@
     @Test public void testWindowFunction() throws Exception {
     	String sql = "select row_number() over (partition by x order by y) from g";
     	Query query = new Query();
-    	WindowFunction wf = new WindowFunction();
+    	WindowFunction wf = new WindowFunction("expr");
     	wf.setFunction(new AggregateSymbol("expr", "ROW_NUMBER", false, null));
     	WindowSpecification ws = new WindowSpecification();
     	ws.setPartition(new ArrayList<Expression>(Arrays.asList(new ElementSymbol("x"))));
     	ws.setOrderBy(new OrderBy(Arrays.asList(new ElementSymbol("y"))));
     	wf.setWindowSpecification(ws);
-    	query.setSelect(new Select(Arrays.asList(new ExpressionSymbol("x", wf))));
+    	query.setSelect(new Select(Arrays.asList(wf)));
     	query.setFrom(new From(Arrays.asList(new UnaryFromClause(new GroupSymbol("g")))));
         helpTest(sql, "SELECT ROW_NUMBER() OVER (PARTITION BY x ORDER BY y) FROM g", query);
     }

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestAggregateProcessing.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestAggregateProcessing.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestAggregateProcessing.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -400,6 +400,23 @@
 		helpProcess(plan, cc, dataManager, expected);
 	}
 	
+	@Test public void testDupGroupCombination() throws Exception {
+        String sql = "select count(e2), e1 from (select distinct e1, e2, e3 from pm1.g1) x group by e1"; //$NON-NLS-1$
+
+        List[] expected = new List[] {
+				Arrays.asList(2, "a"),
+		};
+
+		HardcodedDataManager dataManager = new HardcodedDataManager();
+		dataManager.addData("SELECT pm1.g1.e1, pm1.g1.e2, pm1.g1.e3 FROM pm1.g1", new List[] {
+				Arrays.asList("a", 0, Boolean.TRUE),
+				Arrays.asList("a", 0, Boolean.FALSE),
+		});
+
+		ProcessorPlan plan = helpGetPlan(sql, RealMetadataFactory.example1Cached());
+		helpProcess(plan, dataManager, expected);
+	}
+	
 	@Test public void testAggFilter() throws Exception {
 		// Create query
 		String sql = "SELECT e2, count(*) filter (where e3) from pm1.g1 group by e2 order by e2"; //$NON-NLS-1$

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -4485,6 +4485,30 @@
        helpProcess(plan, dataManager, expected);
    }
    
+    @Test public void testSortGroupCombination() throws Exception {
+        String sql = "select e2, max(e1) from pm1.g1 x group by e2 order by e2 desc"; //$NON-NLS-1$
+
+        FakeDataManager dataManager = new FakeDataManager();
+        sampleData1(dataManager);
+        ProcessorPlan plan = helpGetPlan(sql, RealMetadataFactory.example1Cached(), TestOptimizer.getGenericFinder());
+        
+        helpProcess(plan, dataManager, new List[] {
+                        Arrays.asList(3, "a"),
+                        Arrays.asList(2, "b"),
+                        Arrays.asList(1, "c"),
+                        Arrays.asList(0, "a")});
+    }
+    
+    @Test public void testUnorderedLimitWithProc() throws Exception {
+            String sql = "select e1 from (exec pm1.sq1()) x limit 1";
+        
+        FakeDataManager dataManager = new FakeDataManager();
+        sampleData1(dataManager);
+        ProcessorPlan plan = helpGetPlan(sql, RealMetadataFactory.example1Cached(), TestOptimizer.getGenericFinder());
+        
+        helpProcess(plan, dataManager, new List[] {Arrays.asList("a")});
+    }
+    
    @Test public void testCase3() { 
        // Create query 
        String sql = "SELECT e2, CASE e2 WHEN 1 THEN 2 ELSE null END FROM pm1.g1 WHERE e2 BETWEEN 1 AND 2"; //$NON-NLS-1$
@@ -7574,12 +7598,12 @@
     	String sql = "SELECT pm1.g1.e2 as y FROM pm1.g1 ORDER BY e3 || e1";
         
     	List[] expected = new List[] {
+        		Arrays.asList(1),
         		Arrays.asList(0),
-        		Arrays.asList(1),
+        		Arrays.asList(0),
+        		Arrays.asList(2),
         		Arrays.asList(3),
         		Arrays.asList(1),
-        		Arrays.asList(2),
-        		Arrays.asList(0),
         };
     	
     	FakeDataManager dataManager = new FakeDataManager();

Copied: trunk/engine/src/test/java/org/teiid/query/processor/TestWindowFunctions.java (from rev 3330, trunk/engine/src/test/java/org/teiid/query/optimizer/TestWindowFunctions.java)
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestWindowFunctions.java	                        (rev 0)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestWindowFunctions.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -0,0 +1,131 @@
+/*
+ * 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.processor;
+
+import static org.teiid.query.optimizer.TestOptimizer.*;
+import static org.teiid.query.processor.TestProcessor.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+import org.teiid.query.optimizer.TestOptimizer;
+import org.teiid.query.optimizer.TestOptimizer.ComparisonMode;
+import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
+import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
+import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
+import org.teiid.query.unittest.RealMetadataFactory;
+
+ at SuppressWarnings({"nls", "unchecked"})
+public class TestWindowFunctions {
+
+    @Test public void testViewNotRemoved() throws Exception {
+    	BasicSourceCapabilities caps = getTypicalCapabilities();
+    	caps.setCapabilitySupport(Capability.ELEMENTARY_OLAP, true);
+    	caps.setCapabilitySupport(Capability.QUERY_FROM_INLINE_VIEWS, true);
+        ProcessorPlan plan = TestOptimizer.helpPlan("SELECT y FROM (select row_number() over (order by e1) as y from pm1.g1) as x where x.y = 10", //$NON-NLS-1$
+                                      RealMetadataFactory.example1Cached(), null, new DefaultCapabilitiesFinder(caps),
+                                      new String[] {
+                                          "SELECT v_0.c_0 FROM (SELECT ROW_NUMBER() OVER (ORDER BY g_0.e1) AS c_0 FROM pm1.g1 AS g_0) AS v_0 WHERE v_0.c_0 = 10"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+    
+        checkNodeTypes(plan, FULL_PUSHDOWN);                                    
+    }
+    
+	@Test public void testRanking() throws Exception {
+    	String sql = "select e1, row_number() over (order by e1), rank() over (order by e1), dense_rank() over (order by e1 nulls last) from pm1.g1";
+        
+    	List<?>[] expected = new List[] {
+        		Arrays.asList("a", 2, 2, 1),
+        		Arrays.asList(null, 1, 1, 4),
+        		Arrays.asList("a", 3, 2, 1),
+        		Arrays.asList("c", 6, 6, 3),
+        		Arrays.asList("b", 5, 5, 2),
+        		Arrays.asList("a", 4, 2, 1),
+        };
+    	
+    	FakeDataManager dataManager = new FakeDataManager();
+    	sampleData1(dataManager);
+        ProcessorPlan plan = helpGetPlan(sql, RealMetadataFactory.example1Cached(), TestOptimizer.getGenericFinder());
+        
+        helpProcess(plan, dataManager, expected);
+    }
+    
+    @Test public void testPartitionedMax() throws Exception {
+    	String sql = "select e2, max(e1) over (partition by e2) as y from pm1.g1";
+        
+    	List<?>[] expected = new List[] {
+        		Arrays.asList(0, "a"),
+        		Arrays.asList(1, "c"),
+        		Arrays.asList(3, "a"),
+        		Arrays.asList(1, "c"),
+        		Arrays.asList(2, "b"),
+        		Arrays.asList(0, "a"),
+        };
+    	
+    	FakeDataManager dataManager = new FakeDataManager();
+    	sampleData1(dataManager);
+        ProcessorPlan plan = helpGetPlan(sql, RealMetadataFactory.example1Cached(), TestOptimizer.getGenericFinder());
+        
+        helpProcess(plan, dataManager, expected);
+    }
+    
+    @Test public void testUnrelatedWindowFunctionOrderBy() throws Exception {
+    	String sql = "select e2, e1 from pm1.g1 order by count(e1) over (partition by e3), e2";
+        
+    	List<?>[] expected = new List[] {
+    			Arrays.asList(1, "c"),
+        		Arrays.asList(3, "a"),
+        		Arrays.asList(0, "a"),
+        		Arrays.asList(0, "a"),
+        		Arrays.asList(1, null),
+        		Arrays.asList(2, "b"),
+        };
+    	
+    	FakeDataManager dataManager = new FakeDataManager();
+    	sampleData1(dataManager);
+        ProcessorPlan plan = helpGetPlan(sql, RealMetadataFactory.example1Cached(), TestOptimizer.getGenericFinder());
+        
+        helpProcess(plan, dataManager, expected);
+    }
+    
+    @Test public void testWindowFunctionOrderBy() throws Exception {
+    	String sql = "select e2, e1, count(e1) over (partition by e3) as c from pm1.g1 order by c, e2";
+        
+    	List<?>[] expected = new List[] {
+        		Arrays.asList(1, "c", 2),
+        		Arrays.asList(3, "a", 2),
+        		Arrays.asList(0, "a", 3),
+        		Arrays.asList(0, "a", 3),
+        		Arrays.asList(1, null, 3),
+        		Arrays.asList(2, "b", 3),
+        };
+    	
+    	FakeDataManager dataManager = new FakeDataManager();
+    	sampleData1(dataManager);
+        ProcessorPlan plan = helpGetPlan(sql, RealMetadataFactory.example1Cached(), TestOptimizer.getGenericFinder());
+        
+        helpProcess(plan, dataManager, expected);
+    }
+
+    
+}


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

Modified: trunk/engine/src/test/java/org/teiid/query/processor/relational/TestGroupingNode.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/relational/TestGroupingNode.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/test/java/org/teiid/query/processor/relational/TestGroupingNode.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -22,7 +22,7 @@
 
 package org.teiid.query.processor.relational;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
@@ -45,6 +45,7 @@
 import org.teiid.query.processor.FakeDataManager;
 import org.teiid.query.processor.FakeTupleSource;
 import org.teiid.query.processor.ProcessorDataManager;
+import org.teiid.query.sql.lang.OrderBy;
 import org.teiid.query.sql.symbol.AggregateSymbol;
 import org.teiid.query.sql.symbol.Constant;
 import org.teiid.query.sql.symbol.ElementSymbol;
@@ -153,7 +154,7 @@
 		
 		List groupingElements = new ArrayList();
 		groupingElements.add(col1);
-		node.setGroupingElements(groupingElements);	  
+		node.setOrderBy(new OrderBy(groupingElements).getOrderByItems());
         CommandContext context = new CommandContext("pid", "test", null, null, 1);               //$NON-NLS-1$ //$NON-NLS-2$
         
         List[] expected = new List[] {
@@ -231,8 +232,6 @@
         outputElements.add(new AggregateSymbol("bigAvg", "AVG", false, bigDecimal)); //$NON-NLS-1$ //$NON-NLS-2$
         node.setElements(outputElements);
         
-        // Set grouping elements to null 
-        node.setGroupingElements(null);         
         CommandContext context = new CommandContext("pid", "test", null, null, 1);               //$NON-NLS-1$ //$NON-NLS-2$
         
         List[] data = new List[] {
@@ -272,7 +271,7 @@
         // Set grouping elements to null 
         List groupingElements = new ArrayList();
         groupingElements.add(col1); 
-        node.setGroupingElements(groupingElements);         
+        node.setOrderBy(new OrderBy(groupingElements).getOrderByItems());         
         CommandContext context = new CommandContext("pid", "test", null, null, 1);               //$NON-NLS-1$ //$NON-NLS-2$
         
         List[] data = new List[] {
@@ -320,7 +319,7 @@
         
         List groupingElements = new ArrayList();
         groupingElements.add(col1); 
-        node.setGroupingElements(groupingElements);   
+        node.setOrderBy(new OrderBy(groupingElements).getOrderByItems());   
         CommandContext context = new CommandContext("pid", "test", null, null, 1);    //$NON-NLS-1$ //$NON-NLS-2$
         
         FakeDataManager dataMgr = new FakeDataManager();
@@ -366,7 +365,7 @@
         if (groupBy) {
             List groupingElements = new ArrayList();
             groupingElements.add(new ElementSymbol("col1")); //$NON-NLS-1$
-            node.setGroupingElements(groupingElements);
+            node.setOrderBy(new OrderBy(groupingElements).getOrderByItems());
         }
         CommandContext context = new CommandContext("pid", "test", null, null, 1);               //$NON-NLS-1$ //$NON-NLS-2$
         
@@ -434,7 +433,7 @@
         
         List groupingElements = new ArrayList();
         groupingElements.add(col1); 
-        node.setGroupingElements(groupingElements);
+        node.setOrderBy(new OrderBy(groupingElements).getOrderByItems());
 		return node;
 	}
     

Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java	2011-07-27 14:34:57 UTC (rev 3338)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java	2011-07-27 14:43:28 UTC (rev 3339)
@@ -1896,7 +1896,7 @@
 	}
 
 	@Test public void testWindowFunctionWithNestedOrdering() {
-		helpValidate("SELECT xmlagg(xmlelement(name x, e1) order by e2) over () from pm1.g1", new String[] {"XMLAGG(XMLELEMENT(NAME x, e1) ORDER BY e2)"}, RealMetadataFactory.example1Cached());		
+		helpValidate("SELECT xmlagg(xmlelement(name x, e1) order by e2) over () from pm1.g1", new String[] {"XMLAGG(XMLELEMENT(NAME x, e1) ORDER BY e2) OVER ()"}, RealMetadataFactory.example1Cached());		
 	}
 	
 	@Test public void testWindowFunctionWithNestedaggAllowed() {
@@ -1907,4 +1907,8 @@
 		helpValidate("SELECT max(min(e1)) over (order by max(e2)) from pm1.g1 group by e1", new String[] {"MIN(e1)"}, RealMetadataFactory.example1Cached());		
 	}
 	
+	@Test public void testWindowFunctionWithoutFrom() {
+		helpValidate("select count(*) over () as y", new String[] {"COUNT(*) OVER ()"}, RealMetadataFactory.example1Cached());
+	}
+	
 }



More information about the teiid-commits mailing list