[teiid-commits] teiid SVN: r2140 - in trunk/engine/src: main/java/org/teiid/query/function/aggregate and 15 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Tue May 18 16:54:36 EDT 2010


Author: shawkins
Date: 2010-05-18 16:54:34 -0400 (Tue, 18 May 2010)
New Revision: 2140

Added:
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/XMLAgg.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java
Removed:
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/NullFilter.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/DuplicateFilter.java
   trunk/engine/src/test/java/org/teiid/common/log/
Modified:
   trunk/engine/src/main/java/org/teiid/common/buffer/TupleSource.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/AggregateFunction.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/Avg.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/ConstantFunction.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/Count.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/Max.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/Min.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/Sum.java
   trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/SortUtility.java
   trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverVisitor.java
   trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
   trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
   trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java
   trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
   trunk/engine/src/main/resources/org/teiid/query/i18n.properties
   trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/language/TestAggregateImpl.java
   trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
   trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java
   trunk/engine/src/test/java/org/teiid/query/processor/relational/TestDuplicateFilter.java
   trunk/engine/src/test/java/org/teiid/query/processor/relational/TestGroupingNode.java
Log:
TEIID-171 adding support for xmlagg

Modified: trunk/engine/src/main/java/org/teiid/common/buffer/TupleSource.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/TupleSource.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/TupleSource.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -26,7 +26,7 @@
 
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
-import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.symbol.Expression;
 
 
 /**
@@ -40,7 +40,7 @@
      * Returns the List of ElementSymbol describing the Tuple Source
      * @return the List of elements describing the Tuple Source
      */
-	List<SingleElementSymbol> getSchema();
+	List<? extends Expression> getSchema();
 	
     /**
      * Returns the next tuple

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	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/AggregateFunction.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -22,6 +22,8 @@
 
 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;
@@ -34,8 +36,13 @@
  * being aggregated, then addInput() is called for every row in the group, then
  * getResult() is called to retrieve the result.
  */
-public interface AggregateFunction {
+public abstract class AggregateFunction {
 
+	private int expressionIndex = -1;
+	
+	public void setExpressionIndex(int expressionIndex) {
+		this.expressionIndex = expressionIndex;
+	}
 
     /**
      * Called to initialize the function.  In the future this may expand
@@ -43,21 +50,36 @@
      * @param dataType Data type of element begin aggregated
      * @param inputType
      */
-    public abstract void initialize(Class dataType, Class inputType);
+    public void initialize(Class<?> dataType, Class<?> inputType) {}
 
     /**
      * Called to reset the state of the function.
      */
     public abstract void reset();
 
+    public void addInput(List<?> tuple) throws TeiidComponentException, TeiidProcessingException {
+    	if (expressionIndex == -1) {
+    		addInputDirect(null, tuple);
+    		return;
+    	}
+    	Object input = tuple.get(expressionIndex);
+    	if (!filter(input)) {
+    		addInputDirect(input, tuple);
+    	}
+    }
+    
+    boolean filter(Object value) {
+    	return value == null; 
+    }
+    
     /**
      * Called for the element value in every row of a group.
      * @param input Input value, may be null
+     * @param tuple 
+     * @throws TeiidProcessingException 
      */
-    public abstract void addInput(Object input) 
-        throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException;
+    public abstract void addInputDirect(Object input, List<?> tuple) throws TeiidComponentException, TeiidProcessingException;
 
-
     /**
      * Called after all values have been processed to get the result.
      * @return Result value

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/Avg.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/Avg.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Avg.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -23,6 +23,7 @@
 package org.teiid.query.function.aggregate;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 import org.teiid.api.exception.query.ExpressionEvaluationException;
 import org.teiid.api.exception.query.FunctionExecutionException;
@@ -45,16 +46,9 @@
     private int count = 0;
 
     /**
-     * Constructor for Avg.
-     */
-    public Avg() {
-        super();
-    }
-
-    /**
      * @see org.teiid.query.function.aggregate.AggregateFunction#initialize(String, Class)
      */
-    public void initialize(Class dataType, Class inputType) {
+    public void initialize(Class<?> dataType, Class<?> inputType) {
         if (dataType.equals(DataTypeManager.DefaultDataClasses.BIG_DECIMAL)) {
             this.accumulatorType = BIG_DECIMAL;
         } else {
@@ -68,12 +62,12 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInput(Object)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(Object, List)
      */
-    public void addInput(Object input)
+    public void addInputDirect(Object input, List<?> tuple)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
 
-        super.addInput(input);
+        super.addInputDirect(input, tuple);
         count++;
     }
 

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	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/ConstantFunction.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -22,6 +22,8 @@
 
 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;
@@ -29,31 +31,23 @@
 
 /**
  */
-public class ConstantFunction implements AggregateFunction {
+public class ConstantFunction extends AggregateFunction {
 
     private Object value;
 
-    /**
-     * Constructor for NoFunction.
-     */
-    public ConstantFunction() {
-        super();
-    }
-
-    /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#initialize(String, Class)
-     */
-    public void initialize(Class dataType, Class inputType) {
-    }
-    
     public void reset() {
         this.value = null;
     }
+    
+    @Override
+    boolean filter(Object input) {
+    	return false;
+    }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInput(Object)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(Object, List)
      */
-    public void addInput(Object input)
+    public void addInputDirect(Object input, List<?> tuple)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
             
         value = input;

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/Count.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/Count.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Count.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -22,34 +22,23 @@
 
 package org.teiid.query.function.aggregate;
 
+import java.util.List;
+
 /**
  * Just a simple COUNT() implementation that counts every non-null row it sees.
  */
-public class Count implements AggregateFunction {
+public class Count extends AggregateFunction {
 
     private int count = 0;
 
-    /**
-     * Constructor for Count.
-     */
-    public Count() {
-        super();
-    }
-
-    /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#initialize(String, Class)
-     */
-    public void initialize(Class dataType, Class inputType) {
-    }
-    
     public void reset() {
         count = 0;
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInput(Object)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(Object, List)
      */
-    public void addInput(Object input) {
+    public void addInputDirect(Object input, List<?> tuple) {
         count++;
     }
 

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/Max.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/Max.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Max.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -22,6 +22,8 @@
 
 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;
@@ -31,31 +33,18 @@
 
 /**
  */
-public class Max implements AggregateFunction {
+public class Max extends AggregateFunction {
 
     private Object maxValue;
 
-    /**
-     * Constructor for Min.
-     */
-    public Max() {
-        super();
-    }
-
-    /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#initialize(String, Class)
-     */
-    public void initialize(Class dataType, Class inputType) {
-    }
-
     public void reset() {
         maxValue = null;
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInput(Object)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(Object, List)
      */
-    public void addInput(Object value)
+    public void addInputDirect(Object value, List<?> tuple)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
 
         if(maxValue == null) {

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/Min.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/Min.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Min.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -22,6 +22,8 @@
 
 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;
@@ -31,31 +33,18 @@
 
 /**
  */
-public class Min implements AggregateFunction {
+public class Min extends AggregateFunction {
 
     private Object minValue;
 
-    /**
-     * Constructor for Min.
-     */
-    public Min() {
-        super();
-    }
-
-    /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#initialize(String, Class)
-     */
-    public void initialize(Class dataType, Class inputType) {
-    }
-
     public void reset() {
         minValue = null;
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInput(Object)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(Object, List)
      */
-    public void addInput(Object value)
+    public void addInputDirect(Object value, List<?> tuple)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
 
         if(minValue == null) {

Deleted: trunk/engine/src/main/java/org/teiid/query/function/aggregate/NullFilter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/NullFilter.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/NullFilter.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -1,84 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-package org.teiid.query.function.aggregate;
-
-import org.teiid.api.exception.query.ExpressionEvaluationException;
-import org.teiid.api.exception.query.FunctionExecutionException;
-import org.teiid.core.TeiidComponentException;
-import org.teiid.core.TeiidProcessingException;
-
-
-
-/**
- */
-public class NullFilter implements AggregateFunction {
-
-    private AggregateFunction proxy;
-    
-    /**
-     * Constructor for NullFilter.
-     */
-    public NullFilter(AggregateFunction proxy) {
-        super();
-        
-        this.proxy = proxy;
-    }
-    
-    public AggregateFunction getProxy() {
-		return proxy;
-	}
-
-    /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#initialize(String, Class)
-     */
-    public void initialize(Class dataType, Class inputType) {
-    	this.proxy.initialize(dataType, inputType);
-    }
-
-    public void reset() {
-        this.proxy.reset();
-    }
-    
-    /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInput(Object)
-     */
-    public void addInput(Object input)
-        throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
-        
-        if(input != null) { 
-            this.proxy.addInput(input);
-        } 
-    }
-
-    /**
-     * @throws TeiidProcessingException 
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
-     */
-    public Object getResult()
-        throws TeiidComponentException, TeiidProcessingException {
-            
-        return this.proxy.getResult();
-    }
-
-
-}

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/Sum.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/Sum.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Sum.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -24,6 +24,7 @@
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.util.List;
 
 import org.teiid.api.exception.query.ExpressionEvaluationException;
 import org.teiid.api.exception.query.FunctionExecutionException;
@@ -36,7 +37,7 @@
  * of a column.  The type of the result varies depending on the type
  * of the input {@see AggregateSymbol}
  */
-public class Sum implements AggregateFunction {
+public class Sum extends AggregateFunction {
 
     // Various possible accumulators, depending on type
     protected static final int LONG = 0;
@@ -49,12 +50,6 @@
     private Object sum = null;
 
     /**
-     * Constructor for Sum.
-     */
-    public Sum() {
-    }
-    
-    /**
      * Allows subclasses to determine type of accumulator for the SUM.
      * @return Type, as defined in constants
      */    
@@ -65,7 +60,7 @@
     /**
      * @see org.teiid.query.function.aggregate.AggregateFunction#initialize(boolean, String)
      */
-    public void initialize(Class dataType, Class inputType) {
+    public void initialize(Class<?> dataType, Class<?> inputType) {
         if(dataType.equals(DataTypeManager.DefaultDataClasses.LONG)) {
                     
             this.accumulatorType = LONG;    
@@ -87,9 +82,9 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInput(Object)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(Object, List)
      */
-    public void addInput(Object input)
+    public void addInputDirect(Object input, List<?> tuple)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
         
         if (this.sum == null) {

Added: trunk/engine/src/main/java/org/teiid/query/function/aggregate/XMLAgg.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/XMLAgg.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/XMLAgg.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -0,0 +1,65 @@
+/*
+ * 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.core.TeiidComponentException;
+import org.teiid.core.TeiidProcessingException;
+import org.teiid.core.types.XMLType;
+import org.teiid.query.function.source.XMLSystemFunctions;
+import org.teiid.query.util.CommandContext;
+
+/**
+ * Aggregates XML entries
+ */
+public class XMLAgg extends AggregateFunction {
+
+    private XMLType result;
+    private CommandContext context;
+    
+    public XMLAgg(CommandContext context) {
+    	this.context = context;
+	}
+
+    public void reset() {
+        result = null;
+    }
+
+    /**
+     * @throws TeiidProcessingException 
+     * @throws TeiidComponentException 
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(Object, List)
+     */
+    public void addInputDirect(Object input, List<?> tuple) throws TeiidComponentException, TeiidProcessingException {
+    	result = XMLSystemFunctions.xmlConcat(context, result, input);
+    }
+
+    /**
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     */
+    public Object getResult() {
+        return result;
+    }
+
+}


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

Modified: trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -248,6 +248,9 @@
         } else if(functionType.equals(SQLReservedWords.MAX)) { 
             int num = info.anonMaxCount++;
             return "max" + (num == 0 ? "" : ""+num);//$NON-NLS-1$   //$NON-NLS-2$   //$NON-NLS-3$
+        } else if(functionType.equals(SQLReservedWords.XMLAGG)) { 
+            int num = info.anonMaxCount++;
+            return "xmlagg" + (num == 0 ? "" : ""+num);//$NON-NLS-1$   //$NON-NLS-2$   //$NON-NLS-3$
         } else {
             Object[] params = new Object[] { functionType };
             throw new ParseException(QueryPlugin.Util.getString("SQLParser.Unknown_agg_func", params)); //$NON-NLS-1$

Deleted: trunk/engine/src/main/java/org/teiid/query/processor/relational/DuplicateFilter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/DuplicateFilter.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/DuplicateFilter.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -1,154 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-package org.teiid.query.processor.relational;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.teiid.api.exception.query.ExpressionEvaluationException;
-import org.teiid.api.exception.query.FunctionExecutionException;
-import org.teiid.common.buffer.BufferManager;
-import org.teiid.common.buffer.TupleBuffer;
-import org.teiid.common.buffer.TupleSource;
-import org.teiid.common.buffer.BufferManager.TupleSourceType;
-import org.teiid.core.TeiidComponentException;
-import org.teiid.core.TeiidProcessingException;
-import org.teiid.query.function.aggregate.AggregateFunction;
-import org.teiid.query.processor.relational.SortUtility.Mode;
-import org.teiid.query.sql.lang.OrderBy;
-import org.teiid.query.sql.symbol.ElementSymbol;
-
-
-/**
- */
-public class DuplicateFilter implements AggregateFunction {
-
-    // Initial setup - can be reused
-    private AggregateFunction proxy;
-    private BufferManager mgr;
-    private String groupName;
-
-    // Derived and static - can be reused
-    private List elements;
-    private List sortTypes;
-
-    // Temporary state - should be reset
-    private TupleBuffer collectionBuffer;
-    private SortUtility sortUtility;
-
-    /**
-     * Constructor for DuplicateFilter.
-     */
-    public DuplicateFilter(AggregateFunction proxy, BufferManager mgr, String groupName) {
-        super();
-
-        this.proxy = proxy;
-        this.mgr = mgr;
-        this.groupName = groupName;
-    }
-    
-    public List getElements() {
-		return elements;
-	}
-
-    /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#initialize(String, Class)
-     */
-    public void initialize(Class dataType, Class inputType) {
-    	this.proxy.initialize(dataType, inputType);
-        // Set up schema
-        ElementSymbol element = new ElementSymbol("val"); //$NON-NLS-1$
-        element.setType(inputType);
-        elements = new ArrayList();
-        elements.add(element);
-
-        sortTypes = new ArrayList();
-        sortTypes.add(Boolean.valueOf(OrderBy.ASC));
-    }
-
-    public void reset() {
-        this.proxy.reset();
-        close();
-    }
-
-	private void close() {
-		if (this.collectionBuffer != null) {
-        	collectionBuffer.remove();
-        }
-        this.collectionBuffer = null;
-        this.sortUtility = null;
-	}
-
-    /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInput(Object)
-     */
-    public void addInput(Object input)
-        throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
-
-        if(collectionBuffer == null) {
-            collectionBuffer = mgr.createTupleBuffer(elements, groupName, TupleSourceType.PROCESSOR);
-            collectionBuffer.setForwardOnly(true);
-        }
-
-        List row = new ArrayList(1);
-        row.add(input);
-        this.collectionBuffer.addTuple(row);
-    }
-
-    /**
-     * @throws TeiidProcessingException 
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
-     */
-    public Object getResult()
-        throws TeiidComponentException, TeiidProcessingException {
-
-        if(collectionBuffer != null) {
-            this.collectionBuffer.close();
-
-            // Sort
-            if (sortUtility == null) {
-            	sortUtility = new SortUtility(collectionBuffer.createIndexedTupleSource(), elements, sortTypes, Mode.DUP_REMOVE_SORT, mgr, groupName);
-            }
-            TupleBuffer sorted = sortUtility.sort();
-            sorted.setForwardOnly(true);
-            try {
-	            // Add all input to proxy
-	            TupleSource sortedSource = sorted.createIndexedTupleSource();
-	            while(true) {
-	                List tuple = sortedSource.nextTuple();
-	                if(tuple == null) {
-	                    break;
-	                }
-	                this.proxy.addInput(tuple.get(0));
-	            }
-            } finally {
-            	sorted.remove();
-            }
-            
-            close();
-        }
-
-        // Return
-        return this.proxy.getResult();
-    }
-}

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	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -28,9 +28,9 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 
-import org.teiid.api.exception.query.ExpressionEvaluationException;
 import org.teiid.client.plan.PlanNode;
 import org.teiid.common.buffer.BlockedException;
 import org.teiid.common.buffer.BufferManager;
@@ -47,12 +47,14 @@
 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.NullFilter;
 import org.teiid.query.function.aggregate.Sum;
+import org.teiid.query.function.aggregate.XMLAgg;
 import org.teiid.query.processor.ProcessorDataManager;
 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.util.CommandContext;
@@ -68,7 +70,7 @@
     // Collection phase
     private int phase = COLLECTION;
     private Map elementMap;                    // Map of incoming symbol to index in source elements
-    private List collectedExpressions;         // Collected Expressions
+    private List<Expression> collectedExpressions;         // Collected Expressions
        
     // Sort phase
     private SortUtility sortUtility;
@@ -77,7 +79,6 @@
     
     // Group phase
     private AggregateFunction[] functions;
-    private int[] aggProjectionIndexes;
     private List lastRow;
 	private List currentGroupTuple;
 
@@ -140,33 +141,28 @@
 
     	// List should contain all grouping columns / expressions as we need those for sorting
         if(this.sortElements != null) {
-            this.collectedExpressions = new ArrayList(this.sortElements.size() + getElements().size());
+            this.collectedExpressions = new ArrayList<Expression>(this.sortElements.size() + getElements().size());
             this.collectedExpressions.addAll(sortElements);
         } else {
-            this.collectedExpressions = new ArrayList(getElements().size());
+            this.collectedExpressions = new ArrayList<Expression>(getElements().size());
         }
         
         // Construct aggregate function state accumulators
         functions = new AggregateFunction[getElements().size()];
-        aggProjectionIndexes = new int[getElements().size()];
-        Arrays.fill(aggProjectionIndexes, -1);
         for(int i=0; i<getElements().size(); i++) {
             SingleElementSymbol symbol = (SingleElementSymbol)getElements().get(i);
             Class<?> outputType = symbol.getType();
             Class<?> inputType = symbol.getType();
             if(symbol instanceof AggregateSymbol) {
                 AggregateSymbol aggSymbol = (AggregateSymbol) symbol;
-
+                
                 if(aggSymbol.getExpression() == null) {
                     functions[i] = new Count();
                 } else {
-                	int index = this.collectedExpressions.indexOf(aggSymbol.getExpression());
-                	if(index == -1) {
-                        index = this.collectedExpressions.size();
-                        this.collectedExpressions.add(aggSymbol.getExpression());
-                    }
-                	aggProjectionIndexes[i] = index;
-                    String function = aggSymbol.getAggregateFunction();
+                	Expression ex = aggSymbol.getExpression();
+                	inputType = ex.getType();
+                	int index = collectExpression(ex);
+                	String function = aggSymbol.getAggregateFunction();
                     if(function.equals(SQLReservedWords.COUNT)) {
                         functions[i] = new Count();
                     } else if(function.equals(SQLReservedWords.SUM)) {
@@ -175,24 +171,59 @@
                         functions[i] = new Avg();
                     } else if(function.equals(SQLReservedWords.MIN)) {
                         functions[i] = new Min();
+                    } else if (function.equals(SQLReservedWords.MAX)){
+                        functions[i] = new Max();
                     } else {
-                        functions[i] = new Max();
+                    	functions[i] = new XMLAgg(context);
                     }
 
                     if(aggSymbol.isDistinct() && !function.equals(SQLReservedWords.MIN) && !function.equals(SQLReservedWords.MAX)) {
-                        functions[i] = new DuplicateFilter(functions[i], getBufferManager(), getConnectionID());
-                    }
-                    
-                    functions[i] = new NullFilter(functions[i]);
-                    inputType = aggSymbol.getExpression().getType();
+                        SortingFilter filter = new SortingFilter(functions[i], getBufferManager(), getConnectionID(), true);
+                        ElementSymbol element = new ElementSymbol("val"); //$NON-NLS-1$
+                        element.setType(inputType);
+                        filter.setElements(Arrays.asList(element));
+                        filter.setSortElements(filter.getElements());
+                        functions[i] = filter;
+                    } else if (aggSymbol.getOrderBy() != null) { //handle the xmlagg case
+                		int[] orderIndecies = new int[aggSymbol.getOrderBy().getOrderByItems().size()];
+                		List<Boolean> aggSortTypes = new ArrayList<Boolean>(orderIndecies.length);
+                		List<ElementSymbol> schema = new ArrayList<ElementSymbol>(orderIndecies.length + 1);
+                		ElementSymbol element = new ElementSymbol("val"); //$NON-NLS-1$
+                        element.setType(inputType);
+                        schema.add(element);
+                		for (ListIterator<OrderByItem> iterator = aggSymbol.getOrderBy().getOrderByItems().listIterator(); iterator.hasNext();) {
+                			OrderByItem item = iterator.next();
+                			orderIndecies[iterator.previousIndex()] = collectExpression(item.getSymbol());
+                			aggSortTypes.add(item.isAscending());
+                			element = new ElementSymbol(String.valueOf(iterator.previousIndex()));
+                            element.setType(inputType);
+                			schema.add(element);
+						}
+                		SortingFilter filter = new SortingFilter(functions[i], getBufferManager(), getConnectionID(), false);
+                		filter.setSortTypes(aggSortTypes);
+                		filter.setIndecies(orderIndecies);
+                		filter.setElements(schema);
+                		filter.setSortElements(schema.subList(1, schema.size()));
+                        functions[i] = filter;
+                	}
+                    functions[i].setExpressionIndex(index);
                 }
             } else {
                 functions[i] = new ConstantFunction();
-                aggProjectionIndexes[i] = this.collectedExpressions.indexOf(symbol);
+                functions[i].setExpressionIndex(this.collectedExpressions.indexOf(symbol));
             }
             functions[i].initialize(outputType, inputType);
         }
-    } 
+    }
+
+	private int collectExpression(Expression ex) {
+		int index = this.collectedExpressions.indexOf(ex);
+		if(index == -1) {
+		    index = this.collectedExpressions.size();
+		    this.collectedExpressions.add(ex);
+		}
+		return index;
+	} 
     
     AggregateFunction[] getFunctions() {
 		return functions;
@@ -246,7 +277,7 @@
 		                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 = new Evaluator(elementMap, getDataManager(), getContext()).evaluate((Expression) collectedExpressions.get(col), tuple);
+		                    Object value = new Evaluator(elementMap, getDataManager(), getContext()).evaluate((Expression)collectedExpressions.get(col), tuple);
 		                    exprTuple.add(value);
 		                }
 		                sourceRow++;
@@ -263,7 +294,7 @@
 			}
 			
 			@Override
-			public List<SingleElementSymbol> getSchema() {
+			public List<Expression> getSchema() {
 				return collectedExpressions;
 			}
 			
@@ -382,14 +413,10 @@
     }
 
     private void updateAggregates(List tuple)
-    throws TeiidComponentException, ExpressionEvaluationException {
+    throws TeiidComponentException, TeiidProcessingException {
 
         for(int i=0; i<functions.length; i++) {
-            Object value = null;
-            if(aggProjectionIndexes[i] != -1) {
-                value = tuple.get(aggProjectionIndexes[i]);
-            }
-            functions[i].addInput(value);
+            functions[i].addInput(tuple);
         }
     }
 

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	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/SortUtility.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -42,6 +42,7 @@
 import org.teiid.logging.LogManager;
 import org.teiid.logging.MessageLevel;
 import org.teiid.query.sql.lang.OrderBy;
+import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.symbol.SingleElementSymbol;
 
 
@@ -87,7 +88,7 @@
     private Mode mode;
     private BufferManager bufferManager;
     private String groupName;
-    private List<SingleElementSymbol> schema;
+    private List<? extends Expression> schema;
     private int schemaSize;
 	private ListNestedSortComparator comparator;
 
@@ -120,7 +121,7 @@
 	    		sortTypes = Collections.nCopies(sortElements.size(), OrderBy.ASC);
 	        } else if (sortElements.size() < schema.size()) {
 	        	sortElements = new ArrayList(sortElements);
-	        	List<SingleElementSymbol> toAdd = new ArrayList<SingleElementSymbol>(schema);
+	        	List<Expression> toAdd = new ArrayList<Expression>(schema);
 	        	toAdd.removeAll(sortElements);
 	        	sortElements.addAll(toAdd);
 	        	sortTypes = new ArrayList<Boolean>(sortTypes);

Copied: trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java (from rev 2137, trunk/engine/src/main/java/org/teiid/query/processor/relational/DuplicateFilter.java)
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -0,0 +1,165 @@
+/*
+ * 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.List;
+
+import org.teiid.api.exception.query.ExpressionEvaluationException;
+import org.teiid.api.exception.query.FunctionExecutionException;
+import org.teiid.common.buffer.BufferManager;
+import org.teiid.common.buffer.TupleBuffer;
+import org.teiid.common.buffer.TupleSource;
+import org.teiid.common.buffer.BufferManager.TupleSourceType;
+import org.teiid.core.TeiidComponentException;
+import org.teiid.core.TeiidProcessingException;
+import org.teiid.query.function.aggregate.AggregateFunction;
+import org.teiid.query.processor.relational.SortUtility.Mode;
+
+/**
+ */
+public class SortingFilter extends AggregateFunction {
+
+    private static final int[] NO_INDECIES = new int[0];
+	// Initial setup - can be reused
+    private AggregateFunction proxy;
+    private BufferManager mgr;
+    private String groupName;
+    private boolean removeDuplicates;
+
+    // Derived and static - can be reused
+    private List elements;
+    private List sortTypes;
+    private List sortElements;
+    
+    private int[] indecies = NO_INDECIES;
+
+    // Temporary state - should be reset
+    private TupleBuffer collectionBuffer;
+    private SortUtility sortUtility;
+
+    /**
+     * Constructor for DuplicateFilter.
+     */
+    public SortingFilter(AggregateFunction proxy, BufferManager mgr, String groupName, boolean removeDuplicates) {
+        super();
+
+        this.proxy = proxy;
+        this.mgr = mgr;
+        this.groupName = groupName;
+        this.removeDuplicates = removeDuplicates;
+    }
+    
+    public List getElements() {
+		return elements;
+	}
+    
+    public void setElements(List elements) {
+		this.elements = elements;
+	}
+    
+    public void setSortTypes(List sortTypes) {
+		this.sortTypes = sortTypes;
+	}
+    
+    public void setIndecies(int[] indecies) {
+		this.indecies = indecies;
+	}
+    
+    public void setSortElements(List sortElements) {
+		this.sortElements = sortElements;
+	}
+    
+    /**
+     * @see org.teiid.query.function.aggregate.AggregateFunction#initialize(String, Class)
+     */
+    public void initialize(Class<?> dataType, Class<?> inputType) {
+    	this.proxy.initialize(dataType, inputType);
+    }
+
+    public void reset() {
+        this.proxy.reset();
+        close();
+    }
+
+	private void close() {
+		if (this.collectionBuffer != null) {
+        	collectionBuffer.remove();
+        }
+        this.collectionBuffer = null;
+        this.sortUtility = null;
+	}
+	
+	@Override
+	public void addInputDirect(Object input, List<?> tuple)
+			throws FunctionExecutionException, ExpressionEvaluationException,
+			TeiidComponentException, TeiidProcessingException {
+        if(collectionBuffer == null) {
+            collectionBuffer = mgr.createTupleBuffer(elements, groupName, TupleSourceType.PROCESSOR);
+            collectionBuffer.setForwardOnly(true);
+        }
+        List<Object> row = new ArrayList<Object>(1 + indecies.length);
+        row.add(input);
+        for (int i = 0; i < indecies.length; i++) {
+			row.add(tuple.get(indecies[i]));
+		}
+        this.collectionBuffer.addTuple(row);
+	}
+	
+    /**
+     * @throws TeiidProcessingException 
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     */
+    public Object getResult()
+        throws TeiidComponentException, TeiidProcessingException {
+
+        if(collectionBuffer != null) {
+            this.collectionBuffer.close();
+
+            // Sort
+            if (sortUtility == null) {
+            	sortUtility = new SortUtility(collectionBuffer.createIndexedTupleSource(), sortElements, sortTypes, removeDuplicates?Mode.DUP_REMOVE_SORT:Mode.SORT, mgr, groupName);
+            }
+            TupleBuffer sorted = sortUtility.sort();
+            sorted.setForwardOnly(true);
+            try {
+	            // Add all input to proxy
+	            TupleSource sortedSource = sorted.createIndexedTupleSource();
+	            while(true) {
+	                List tuple = sortedSource.nextTuple();
+	                if(tuple == null) {
+	                    break;
+	                }
+	                this.proxy.addInputDirect(tuple.get(0), null);
+	            }
+            } finally {
+            	sorted.remove();
+            }
+            
+            close();
+        }
+
+        // Return
+        return this.proxy.getResult();
+    }
+}

Modified: trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverVisitor.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverVisitor.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -627,13 +627,11 @@
 	        if (! type.equals(DataTypeManager.DefaultDataTypes.STRING) &&
 	            ! type.equals(DataTypeManager.DefaultDataTypes.CLOB)) {
 	                
-	            if(!(expr instanceof AggregateSymbol) &&
-	                ResolverUtil.canImplicitlyConvert(type, DataTypeManager.DefaultDataTypes.STRING)) {
+	            if(ResolverUtil.canImplicitlyConvert(type, DataTypeManager.DefaultDataTypes.STRING)) {
 	
 	                result = ResolverUtil.convertExpression(expr, type, DataTypeManager.DefaultDataTypes.STRING, metadata);
 	                
-	            } else if (!(expr instanceof AggregateSymbol) &&
-	                ResolverUtil.canImplicitlyConvert(type, DataTypeManager.DefaultDataTypes.CLOB)){
+	            } else if (ResolverUtil.canImplicitlyConvert(type, DataTypeManager.DefaultDataTypes.CLOB)){
 	                    
 	                result = ResolverUtil.convertExpression(expr, type, DataTypeManager.DefaultDataTypes.CLOB, metadata);
 	
@@ -666,9 +664,6 @@
 	        Expression value = (Expression) valIter.next();
 	        setDesiredType(value, exprType, scrit);
 	        if(! value.getType().equals(exprType)) {
-	            if(value instanceof AggregateSymbol) {
-	                throw new QueryResolverException(ErrorMessageKeys.RESOLVER_0031, QueryPlugin.Util.getString(ErrorMessageKeys.RESOLVER_0031, scrit));
-	            }
 	            // try to apply cast
 	            String valTypeName = DataTypeManager.getDataTypeName(value.getType());
 	            if(ResolverUtil.canImplicitlyConvert(valTypeName, exprTypeName)) {

Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -759,7 +759,7 @@
      * @param query
      * @throws TeiidComponentException, MetaMatrixProcessingException
      */
-    public QueryCommand rewriteOrderBy(QueryCommand queryCommand) throws TeiidComponentException, TeiidProcessingException{
+    public QueryCommand rewriteOrderBy(QueryCommand queryCommand) throws TeiidComponentException {
     	final OrderBy orderBy = queryCommand.getOrderBy();
         if (orderBy == null) {
             return queryCommand;

Modified: trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -132,6 +132,7 @@
     public void visit(AggregateSymbol obj) {
         preVisitVisitor(obj);
         visitNode(obj.getExpression());
+        visitNode(obj.getOrderBy());
         postVisitVisitor(obj);
     }
     public void visit(AliasSymbol obj) {

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	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -33,6 +33,7 @@
 import org.teiid.language.SQLReservedWords;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.sql.LanguageVisitor;
+import org.teiid.query.sql.lang.OrderBy;
 import org.teiid.query.util.ErrorMessageKeys;
 
 
@@ -59,21 +60,23 @@
 
 	private String aggregate;
 	private boolean distinct;
+	private OrderBy orderBy;
 
-	private static final Class COUNT_TYPE = DataTypeManager.getDataTypeClass(DataTypeManager.DefaultDataTypes.INTEGER);
-	private static final Set AGGREGATE_FUNCTIONS;
-	private static final Map SUM_TYPES;
-    private static final Map AVG_TYPES;
+	private static final Class<Integer> COUNT_TYPE = DataTypeManager.DefaultDataClasses.INTEGER;
+	private static final Set<String> AGGREGATE_FUNCTIONS;
+	private static final Map<Class<?>, Class<?>> SUM_TYPES;
+    private static final Map<Class<?>, Class<?>> AVG_TYPES;
 
 	static {
-		AGGREGATE_FUNCTIONS = new HashSet();
+		AGGREGATE_FUNCTIONS = new HashSet<String>();
 		AGGREGATE_FUNCTIONS.add(SQLReservedWords.COUNT);
 		AGGREGATE_FUNCTIONS.add(SQLReservedWords.SUM);
 		AGGREGATE_FUNCTIONS.add(SQLReservedWords.AVG);
 		AGGREGATE_FUNCTIONS.add(SQLReservedWords.MIN);
 		AGGREGATE_FUNCTIONS.add(SQLReservedWords.MAX);
+		AGGREGATE_FUNCTIONS.add(SQLReservedWords.XMLAGG);
 
-		SUM_TYPES = new HashMap();
+		SUM_TYPES = new HashMap<Class<?>, Class<?>>();
 		SUM_TYPES.put(DataTypeManager.DefaultDataClasses.BYTE, DataTypeManager.DefaultDataClasses.LONG);
 		SUM_TYPES.put(DataTypeManager.DefaultDataClasses.SHORT, DataTypeManager.DefaultDataClasses.LONG);
 		SUM_TYPES.put(DataTypeManager.DefaultDataClasses.INTEGER, DataTypeManager.DefaultDataClasses.LONG);
@@ -83,7 +86,7 @@
 		SUM_TYPES.put(DataTypeManager.DefaultDataClasses.DOUBLE, DataTypeManager.DefaultDataClasses.DOUBLE);
 		SUM_TYPES.put(DataTypeManager.DefaultDataClasses.BIG_DECIMAL, DataTypeManager.DefaultDataClasses.BIG_DECIMAL);
         
-        AVG_TYPES = new HashMap();
+        AVG_TYPES = new HashMap<Class<?>, Class<?>>();
         AVG_TYPES.put(DataTypeManager.DefaultDataClasses.BYTE, DataTypeManager.DefaultDataClasses.DOUBLE);
         AVG_TYPES.put(DataTypeManager.DefaultDataClasses.SHORT, DataTypeManager.DefaultDataClasses.DOUBLE);
         AVG_TYPES.put(DataTypeManager.DefaultDataClasses.INTEGER, DataTypeManager.DefaultDataClasses.DOUBLE);
@@ -167,15 +170,15 @@
 	 * type of the contained expression
 	 * @return Type of the symbol
 	 */
-	public Class getType() {
+	public Class<?> getType() {
 		if(this.aggregate.equals(SQLReservedWords.COUNT)) {
 			return COUNT_TYPE;
 		} else if(this.aggregate.equals(SQLReservedWords.SUM) ) {
-			Class expressionType = this.getExpression().getType();
-			return (Class) SUM_TYPES.get(expressionType);
+			Class<?> expressionType = this.getExpression().getType();
+			return SUM_TYPES.get(expressionType);
         } else if (this.aggregate.equals(SQLReservedWords.AVG)) {
-            Class expressionType = this.getExpression().getType();
-            return (Class) AVG_TYPES.get(expressionType);
+            Class<?> expressionType = this.getExpression().getType();
+            return AVG_TYPES.get(expressionType);
 		} else {
 			return this.getExpression().getType();
 		}
@@ -184,6 +187,14 @@
     public void acceptVisitor(LanguageVisitor visitor) {
         visitor.visit(this);
     }
+    
+    public OrderBy getOrderBy() {
+		return orderBy;
+	}
+    
+    public void setOrderBy(OrderBy orderBy) {
+		this.orderBy = orderBy;
+	}
 
 	/**
 	 * Return a deep copy of this object
@@ -195,7 +206,9 @@
 		} else {
 			copy = new AggregateSymbol(getName(), getCanonical(), getAggregateFunction(), isDistinct(), null);
 		}
-
+		if (orderBy != null) {
+			copy.setOrderBy(orderBy.clone());
+		}
 		return copy;
 	}
     
@@ -219,7 +232,8 @@
         
         return this.aggregate.equals(other.aggregate)
                && this.distinct == other.distinct
-               && EquivalenceUtil.areEqual(this.getExpression(), other.getExpression());
+               && EquivalenceUtil.areEqual(this.getExpression(), other.getExpression())
+        	   && EquivalenceUtil.areEqual(this.getOrderBy(), other.getOrderBy());
     }
 
 }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -1104,6 +1104,11 @@
 		} else {
 			parts.add(registerNode(obj.getExpression()));
 		}
+		
+		if (obj.getOrderBy() != null) {
+			parts.add(SPACE);
+			parts.add(registerNode(obj.getOrderBy()));
+		}
 		parts.add(")"); //$NON-NLS-1$
     }
 

Modified: trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -74,6 +74,8 @@
         String aggregateFunction = obj.getAggregateFunction();
         if((aggregateFunction.equals(SQLReservedWords.SUM) || aggregateFunction.equals(SQLReservedWords.AVG)) && obj.getType() == null) {
             handleValidationError(QueryPlugin.Util.getString(ErrorMessageKeys.VALIDATOR_0041, new Object[] {aggregateFunction, obj}), obj);
+        } else if (aggregateFunction.equals(SQLReservedWords.XMLAGG) && obj.getType() != DataTypeManager.DefaultDataClasses.XML) {
+        	handleValidationError(QueryPlugin.Util.getString("AggregateValidationVisitor.non_xml", new Object[] {aggregateFunction, obj}), obj);
         }
         if((obj.isDistinct() || aggregateFunction.equals(SQLReservedWords.MIN) || aggregateFunction.equals(SQLReservedWords.MAX)) && DataTypeManager.isNonComparable(DataTypeManager.getDataTypeName(aggExp.getType()))) {
     		handleValidationError(QueryPlugin.Util.getString("AggregateValidationVisitor.non_comparable", new Object[] {aggregateFunction, obj}), obj); //$NON-NLS-1$

Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2010-05-18 20:54:34 UTC (rev 2140)
@@ -1688,6 +1688,7 @@
 	AggregateSymbol agg = null;
 	boolean isDistinct = false;
 	Expression expression = null;
+	OrderBy orderBy = null;
 }
 {
     // Things that can be aliased    
@@ -1704,13 +1705,23 @@
 				functionToken = <SUM> | 
 				functionToken = <AVG> |
 				functionToken = <MIN> |
-				functionToken = <MAX>
+				functionToken = <MAX> 
 			)
 			<LPAREN>
 			[ <DISTINCT> {isDistinct=true;} ]
 			expression = expression(info)
 			<RPAREN>
-		)             
+		) 
+		| 
+		(
+			functionToken = <XMLAGG>
+			<LPAREN>
+			expression = expression(info)
+			[
+				orderBy = orderby(info)
+			]
+			<RPAREN>
+		)            
 	)
 	{
 		if(! info.aggregatesAllowed) {
@@ -1726,7 +1737,7 @@
 			// COUNT(*)			
 			agg = new AggregateSymbol(name, func, false, null);
 		}
-		
+		agg.setOrderBy(orderBy);
 		return agg;
 	}
 }

Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-05-18 20:54:34 UTC (rev 2140)
@@ -300,6 +300,7 @@
 ERR.015.012.0040 = Aggregate expression has unknown data type: {0}
 ERR.015.012.0041 = The aggregate function {0} cannot be used with non-numeric expressions: {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}
 ERR.015.012.0042 = Cross join may not have criteria: {0}
 ERR.015.012.0043 = Join must have criteria declared in the ON clause: {0}
 ERR.015.012.0045 = Elements in this join criteria are not from a group involved in the join: {0}
@@ -768,7 +769,7 @@
 SystemSource.xpath_description=Evaluate the XPath expression against a document
 SystemSource.xpath_param1=Source document
 SystemSource.xpath_param2=XPath expression
-SystemSource.xpath_param2=Namespaces
+SystemSource.xpath_param3=Namespaces
 SystemSource.xpathvalue_result=Single result
 SystemSource.xpath_result=XPath result
 SystemSource.xsltransform_description=Transform the document with the given stylesheet. 

Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/language/TestAggregateImpl.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/language/TestAggregateImpl.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/language/TestAggregateImpl.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -47,7 +47,7 @@
                                                      functionName,
                                                      distinct,
                                                       new Constant(new Integer(value)));
-        return (AggregateFunction)TstLanguageBridgeFactory.factory.translate(symbol);
+        return TstLanguageBridgeFactory.factory.translate(symbol);
         
     }
 

Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -37,6 +37,7 @@
 import org.teiid.client.metadata.ParameterInfo;
 import org.teiid.core.TeiidException;
 import org.teiid.core.types.DataTypeManager;
+import org.teiid.language.SQLReservedWords;
 import org.teiid.query.sql.lang.BetweenCriteria;
 import org.teiid.query.sql.lang.Command;
 import org.teiid.query.sql.lang.CompareCriteria;
@@ -6732,5 +6733,14 @@
     	f.setNamespaces(new XMLNamespaces(Arrays.asList(new XMLNamespaces.NamespaceItem(), new XMLNamespaces.NamespaceItem("x", "http://foo"))));
     	helpTestExpression("xmlforest(xmlnamespaces(no default, 'http://foo' as x), a as \"table\")", "XMLFOREST(XMLNAMESPACES(NO DEFAULT, 'http://foo' AS x), a AS \"table\")", f);
     }
+    
+    @Test public void testXmlAggWithOrderBy() throws Exception {
+        String sql = "SELECT xmlAgg(1 order by e2)"; //$NON-NLS-1$
+        AggregateSymbol as = new AggregateSymbol("foo", SQLReservedWords.XMLAGG, false, new Constant(1));
+        as.setOrderBy(new OrderBy(Arrays.asList(new ElementSymbol("e2"))));
+        Query query = new Query();
+        query.setSelect(new Select(Arrays.asList(as)));
+        helpTest(sql, "SELECT XMLAGG(1 ORDER BY e2)", query);
+    }
 
 }

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -171,5 +171,35 @@
         
         helpProcess(plan, dataManager, expected);
     }
+    
+    @Test public void testXmlAgg() {
+        String sql = "SELECT xmlelement(parent, xmlAgg(xmlelement(x, xmlattributes(e1, e2)))) from pm1.g1"; //$NON-NLS-1$
+        
+        List[] expected = new List[] {
+        		Arrays.asList("<parent><x e1=\"a\" e2=\"0\"></x><x e2=\"1\"></x><x e1=\"a\" e2=\"3\"></x><x e1=\"c\" e2=\"1\"></x><x e1=\"b\" e2=\"2\"></x><x e1=\"a\" e2=\"0\"></x></parent>"), 
+        };    
+    
+        FakeDataManager dataManager = new FakeDataManager();
+        sampleData1(dataManager);
+        
+        ProcessorPlan plan = helpGetPlan(helpParse(sql), FakeMetadataFactory.example1Cached());
+        
+        helpProcess(plan, dataManager, expected);
+    }
+    
+    @Test public void testXmlAggOrderBy() {
+        String sql = "SELECT xmlelement(parent, xmlAgg(xmlelement(x, xmlattributes(e1, e2)) order by e2)) from pm1.g1"; //$NON-NLS-1$
+        
+        List[] expected = new List[] {
+        		Arrays.asList("<parent><x e1=\"a\" e2=\"0\"></x><x e1=\"a\" e2=\"0\"></x><x e2=\"1\"></x><x e1=\"c\" e2=\"1\"></x><x e1=\"b\" e2=\"2\"></x><x e1=\"a\" e2=\"3\"></x></parent>"), 
+        };    
+    
+        FakeDataManager dataManager = new FakeDataManager();
+        sampleData1(dataManager);
+        
+        ProcessorPlan plan = helpGetPlan(helpParse(sql), FakeMetadataFactory.example1Cached());
+        
+        helpProcess(plan, dataManager, expected);
+    }
 
 }

Modified: trunk/engine/src/test/java/org/teiid/query/processor/relational/TestDuplicateFilter.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/relational/TestDuplicateFilter.java	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/test/java/org/teiid/query/processor/relational/TestDuplicateFilter.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -22,13 +22,16 @@
 
 package org.teiid.query.processor.relational;
 
+import java.util.Arrays;
+
 import org.teiid.common.buffer.BufferManager;
 import org.teiid.common.buffer.BufferManagerFactory;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
 import org.teiid.core.types.DataTypeManager;
 import org.teiid.query.function.aggregate.Count;
-import org.teiid.query.processor.relational.DuplicateFilter;
+import org.teiid.query.processor.relational.SortingFilter;
+import org.teiid.query.sql.symbol.ElementSymbol;
 
 import junit.framework.TestCase;
 
@@ -48,13 +51,17 @@
     public void helpTestDuplicateFilter(Object[] input, Class dataType, int expected) throws TeiidComponentException, TeiidProcessingException {
         BufferManager mgr = BufferManagerFactory.getStandaloneBufferManager();
         
-        DuplicateFilter filter = new DuplicateFilter(new Count(), mgr, "test"); //$NON-NLS-1$
+        SortingFilter filter = new SortingFilter(new Count(), mgr, "test", true); //$NON-NLS-1$
         filter.initialize(dataType, dataType);
+        ElementSymbol element = new ElementSymbol("val"); //$NON-NLS-1$
+        element.setType(dataType);
+        filter.setElements(Arrays.asList(element));
+        filter.setSortElements(filter.getElements());
         filter.reset();
         
         // Add inputs
         for(int i=0; i<input.length; i++) {
-            filter.addInput(input[i]);    
+            filter.addInputDirect(input[i], null);    
         }        
         
         Integer actual = (Integer) filter.getResult();

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	2010-05-18 17:06:12 UTC (rev 2139)
+++ trunk/engine/src/test/java/org/teiid/query/processor/relational/TestGroupingNode.java	2010-05-18 20:54:34 UTC (rev 2140)
@@ -44,13 +44,9 @@
 import org.teiid.query.function.FunctionDescriptor;
 import org.teiid.query.function.SystemFunctionManager;
 import org.teiid.query.function.aggregate.AggregateFunction;
-import org.teiid.query.function.aggregate.NullFilter;
 import org.teiid.query.processor.FakeDataManager;
 import org.teiid.query.processor.FakeTupleSource;
 import org.teiid.query.processor.ProcessorDataManager;
-import org.teiid.query.processor.relational.DuplicateFilter;
-import org.teiid.query.processor.relational.GroupingNode;
-import org.teiid.query.processor.relational.RelationalNode;
 import org.teiid.query.sql.symbol.AggregateSymbol;
 import org.teiid.query.sql.symbol.Constant;
 import org.teiid.query.sql.symbol.ElementSymbol;
@@ -177,7 +173,7 @@
         //ensure that the distinct input type is correct
         AggregateFunction[] functions = node.getFunctions();
         AggregateFunction countDist = functions[5];
-        DuplicateFilter dup = (DuplicateFilter)((NullFilter)countDist).getProxy();
+        SortingFilter dup = (SortingFilter)countDist;
         assertEquals(DataTypeManager.DefaultDataClasses.INTEGER, ((ElementSymbol)dup.getElements().get(0)).getType());
 	}
 



More information about the teiid-commits mailing list