[teiid-commits] teiid SVN: r3973 - in trunk: engine/src/main/java/org/teiid/dqp/internal/datamgr and 16 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Wed Apr 4 15:55:00 EDT 2012


Author: shawkins
Date: 2012-04-04 15:54:58 -0400 (Wed, 04 Apr 2012)
New Revision: 3973

Added:
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/UserDefined.java
Modified:
   trunk/api/src/main/java/org/teiid/UserDefinedAggregate.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/ExecutionContextImpl.java
   trunk/engine/src/main/java/org/teiid/query/QueryPlugin.java
   trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
   trunk/engine/src/main/java/org/teiid/query/function/FunctionDescriptor.java
   trunk/engine/src/main/java/org/teiid/query/function/FunctionTree.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/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/RankingFunction.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/SingleArgumentAggregateFunction.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/StatsFunction.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/Sum.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/XMLAgg.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/AccessNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/WindowFunctionProjectNode.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/lang/Query.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.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/query/function/TestFunctionLibrary.java
   trunk/engine/src/test/java/org/teiid/query/function/TestFunctionTree.java
   trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
   trunk/engine/src/test/java/org/teiid/query/processor/relational/TestDuplicateFilter.java
Log:
TEIID-1560 adding parsing/validation/processing logic for aggregates.  more to come

Modified: trunk/api/src/main/java/org/teiid/UserDefinedAggregate.java
===================================================================
--- trunk/api/src/main/java/org/teiid/UserDefinedAggregate.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/api/src/main/java/org/teiid/UserDefinedAggregate.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -27,8 +27,16 @@
  * @param <T>
  */
 public interface UserDefinedAggregate<T> {
-	
-	void init(CommandContext commandContext);
-	T getResult();
+	/**
+	 * Called when state from the current partition can be forgotten
+	 */
+	void reset();
+	/**
+	 * Called to get the current value.  May be called multiple times in the same 
+	 * partition for windowed aggregates.
+	 * @param commandContext
+	 * @return
+	 */
+	T getResult(CommandContext commandContext);
 
 }

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/ExecutionContextImpl.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/ExecutionContextImpl.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/ExecutionContextImpl.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -33,6 +33,7 @@
 
 import org.teiid.adminapi.Session;
 import org.teiid.common.buffer.BufferManager;
+import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.core.util.HashCodeUtil;
 import org.teiid.dqp.internal.process.RequestWorkItem;
 import org.teiid.dqp.message.RequestID;
@@ -145,23 +146,10 @@
             return false;
         } 
         ExecutionContext other = (ExecutionContext) obj;
-        return compareWithNull(this.getRequestId(), other.getRequestId()) && 
-                compareWithNull(this.getPartIdentifier(), other.getPartIdentifier());
+        return EquivalenceUtil.areEqual(this.getRequestId(), other.getRequestId()) && 
+        EquivalenceUtil.areEqual(this.getPartIdentifier(), other.getPartIdentifier());
     }
 
-    private boolean compareWithNull(Object obj1, Object obj2) {
-        if(obj1 == null) { 
-            if(obj2 == null) {
-                return true;
-            }
-            return false;
-        }
-        if(obj2 == null) {
-            return false;
-        }
-        return obj1.equals(obj2);
-    }
-
     public int hashCode() {
         return HashCodeUtil.hashCode(HashCodeUtil.hashCode(0, getRequestId()), partID);
     }

Modified: trunk/engine/src/main/java/org/teiid/query/QueryPlugin.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/QueryPlugin.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/QueryPlugin.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -612,7 +612,7 @@
 		TEIID30581,
 		TEIID30590,
 		TEIID30591,
-		TEIID30600, TEIID30601, //User defined aggregate errors
+		TEIID30600, TEIID30601, TEIID30602, //User defined aggregate errors
 		
     	TEIID31069,
     	TEIID31070,

Modified: trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -59,8 +59,6 @@
 import org.teiid.core.types.basic.StringToSQLXMLTransform;
 import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.language.Like.MatchMode;
-import org.teiid.metadata.FunctionMethod.Determinism;
-import org.teiid.metadata.FunctionMethod.PushDown;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.function.FunctionDescriptor;
 import org.teiid.query.function.FunctionLibrary;
@@ -970,11 +968,8 @@
 	        values[i+start] = internalEvaluate(args[i], tuple);
 	    }            
 	    
-	    // Check for function we can't evaluate
-	    if(fd.getPushdown() == PushDown.MUST_PUSHDOWN) {
-	         throw new TeiidComponentException(QueryPlugin.Event.TEIID30341, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30341, fd.getName()));
-	    }
-	
+	    fd.checkNotPushdown();	
+	    
 	    // Check for special lookup function
 	    if(fd.getName().equalsIgnoreCase(FunctionLibrary.LOOKUP)) {
 	        if(dataMgr == null) {
@@ -993,13 +988,7 @@
 	    }
 	    
 		// Execute function
-		Object result = fd.invokeFunction(values);
-		
-        if (context != null && fd.getDeterministic().ordinal() <= Determinism.USER_DETERMINISTIC.ordinal()) {
-        	context.setDeterminismLevel(fd.getDeterministic());
-        }
-
-		return result;        
+		return fd.invokeFunction(values, context, null);
 	}
 	
 	private Object evaluate(ScalarSubquery scalarSubquery, List<?> tuple)

Modified: trunk/engine/src/main/java/org/teiid/query/function/FunctionDescriptor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/FunctionDescriptor.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/FunctionDescriptor.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -37,6 +37,7 @@
 import org.teiid.metadata.FunctionMethod.Determinism;
 import org.teiid.metadata.FunctionMethod.PushDown;
 import org.teiid.query.QueryPlugin;
+import org.teiid.query.util.CommandContext;
 
 
 /**
@@ -74,6 +75,16 @@
         this.method = method;
 	}
 	
+	public Object newInstance() {
+		try {
+			return invocationMethod.getDeclaringClass().newInstance();
+		} catch (InstantiationException e) {
+			throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30602, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30602, method.getName(), method.getInvocationClass()));
+		} catch (IllegalAccessException e) {
+			throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30602, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30602, method.getName(), method.getInvocationClass()));
+		}
+	}
+	
 	public void setHasWrappedArgs(boolean hasWrappedArgs) {
 		this.hasWrappedArgs = hasWrappedArgs;
 	}
@@ -165,17 +176,25 @@
 	public void setMetadataID(Object metadataID) {
 		this.metadataID = metadataID;
 	}
+	
+	public void checkNotPushdown() throws FunctionExecutionException {
+	    // Check for function we can't evaluate
+	    if(getPushdown() == PushDown.MUST_PUSHDOWN) {
+	         throw new FunctionExecutionException(QueryPlugin.Event.TEIID30341, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30341, getName()));
+	    }
+	}
 
 	/**
 	 * Invoke the function described in the function descriptor, using the
 	 * values provided.  Return the result of the function.
-	 * @param fd Function descriptor describing the name and types of the arguments
 	 * @param values Values that should match 1-to-1 with the types described in the
 	 * function descriptor
+	 * @param context 
+	 * @param functionTarget TODO
+	 * @param fd Function descriptor describing the name and types of the arguments
 	 * @return Result of invoking the function
 	 */
-	public Object invokeFunction(Object[] values) throws FunctionExecutionException {
-
+	public Object invokeFunction(Object[] values, CommandContext context, Object functionTarget) throws FunctionExecutionException {
         if (!isNullDependent()) {
         	for (int i = requiresContext?1:0; i < values.length; i++) {
 				if (values[i] == null) {
@@ -206,7 +225,10 @@
         		newValues[i - 1] = Arrays.copyOfRange(values, i - 1, values.length);
         		values = newValues;
         	}
-            Object result = invocationMethod.invoke(null, values);
+            Object result = invocationMethod.invoke(functionTarget, values);
+            if (context != null && getDeterministic().ordinal() <= Determinism.USER_DETERMINISTIC.ordinal()) {
+            	context.setDeterminismLevel(getDeterministic());
+            }
             return importValue(result, getReturnType());
         } catch(ArithmeticException e) {
     		 throw new FunctionExecutionException(QueryPlugin.Event.TEIID30383, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30383, getName()));

Modified: trunk/engine/src/main/java/org/teiid/query/function/FunctionTree.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/FunctionTree.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/FunctionTree.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -327,7 +327,7 @@
             if (invocationMethod != null) {
             	// Check return type is non void
         		Class<?> methodReturn = invocationMethod.getReturnType();
-        		if(methodReturn.equals(Void.TYPE)) {
+        		if(method.getAggregateAttributes() == null && methodReturn.equals(Void.TYPE)) {
         			 throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30390, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30390, method.getName(), invocationMethod));
         		}
 
@@ -347,12 +347,15 @@
         		}
         		
         		if (method.getAggregateAttributes() != null && !(UserDefinedAggregate.class.isAssignableFrom(method.getClass()))) {
-        			throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30601, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30601, method.getName(), method.getInvocationClass(), UserDefinedAggregate.class.getName()));
+    				throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30601, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30601, method.getName(), method.getInvocationClass(), UserDefinedAggregate.class.getName()));
         		}
             }
         }
 
         FunctionDescriptor result = new FunctionDescriptor(method, types, outputType, invocationMethod, requiresContext);
+        if (method.getAggregateAttributes() != null) {
+        	result.newInstance();
+        }
         result.setHasWrappedArgs(hasWrappedArg);
         return result;
 	}

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/AggregateFunction.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -28,6 +28,7 @@
 import org.teiid.api.exception.query.FunctionExecutionException;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
+import org.teiid.query.util.CommandContext;
 
 
 /**
@@ -66,7 +67,7 @@
      */
     public abstract void reset();
 
-    public void addInput(List<?> tuple) throws TeiidComponentException, TeiidProcessingException {
+    public void addInput(List<?> tuple, CommandContext commandContext) throws TeiidComponentException, TeiidProcessingException {
     	if (conditionIndex != -1 && !Boolean.TRUE.equals(tuple.get(conditionIndex))) {
 			return;
     	}
@@ -77,7 +78,7 @@
     			}
     		}
     	}
-		addInputDirect(tuple);
+		addInputDirect(tuple, commandContext);
     }
     
     public boolean respectsNull() {
@@ -87,16 +88,18 @@
     /**
      * Called for the element value in every row of a group.
      * @param tuple 
+     * @param commandContext
      * @throws TeiidProcessingException 
      */
-    public abstract void addInputDirect(List<?> tuple) throws TeiidComponentException, TeiidProcessingException;
+    public abstract void addInputDirect(List<?> tuple, CommandContext commandContext) throws TeiidComponentException, TeiidProcessingException;
 
     /**
      * Called after all values have been processed to get the result.
+     * @param commandContext
      * @return Result value
      * @throws TeiidProcessingException 
      */
-    public abstract Object getResult()
+    public abstract Object getResult(CommandContext commandContext)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException, TeiidProcessingException;
 
 }

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/ArrayAgg.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -33,14 +33,9 @@
 public class ArrayAgg extends SingleArgumentAggregateFunction {
 	
     private ArrayList<Object> result;
-    private CommandContext context;
     
-    public ArrayAgg(CommandContext context) {
-    	this.context = context;
-    }
-
 	@Override
-	public void addInputDirect(Object input, List<?> tuple) throws TeiidComponentException, TeiidProcessingException {
+	public void addInputDirect(Object input, List<?> tuple, CommandContext commandContext) throws TeiidComponentException, TeiidProcessingException {
 		if (this.result == null) {
 			this.result = new ArrayList<Object>();
 		}
@@ -51,7 +46,7 @@
 	}
 
 	@Override
-	public Object getResult() throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException,TeiidProcessingException {
+	public Object getResult(CommandContext commandContext) throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException,TeiidProcessingException {
 		if (this.result == null) {
 			return null;
 		}

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Avg.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -31,6 +31,7 @@
 import org.teiid.core.types.DataTypeManager;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.function.FunctionMethods;
+import org.teiid.query.util.CommandContext;
 
 
 /**
@@ -60,22 +61,22 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List, CommandContext, CommandContext)
      */
-    public void addInputDirect(Object input, List<?> tuple)
+    public void addInputDirect(Object input, List<?> tuple, CommandContext commandContext)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
 
-        super.addInputDirect(input, tuple);
+        super.addInputDirect(input, tuple, commandContext);
         count++;
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult(CommandContext)
      */
-    public Object getResult()
+    public Object getResult(CommandContext commandContext)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
 
-        Object sum = super.getResult();
+        Object sum = super.getResult(commandContext);
         if (count == 0 || sum == null) {
             return null;
         }

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/ConstantFunction.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -27,6 +27,7 @@
 import org.teiid.api.exception.query.ExpressionEvaluationException;
 import org.teiid.api.exception.query.FunctionExecutionException;
 import org.teiid.core.TeiidComponentException;
+import org.teiid.query.util.CommandContext;
 
 
 /**
@@ -45,18 +46,18 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List, CommandContext, CommandContext)
      */
-    public void addInputDirect(Object input, List<?> tuple)
+    public void addInputDirect(Object input, List<?> tuple, CommandContext commandContext)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
             
         value = input;
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult(CommandContext)
      */
-    public Object getResult()
+    public Object getResult(CommandContext commandContext)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
             
         return this.value;

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Count.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -26,6 +26,7 @@
 
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
+import org.teiid.query.util.CommandContext;
 
 /**
  * Just a simple COUNT() implementation that counts every non-null row it sees.
@@ -39,15 +40,15 @@
     }
     
     @Override
-    public void addInputDirect(List<?> tuple)
+    public void addInputDirect(List<?> tuple, CommandContext commandContext)
     		throws TeiidComponentException, TeiidProcessingException {
         count++;
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult(CommandContext)
      */
-    public Object getResult() {
+    public Object getResult(CommandContext commandContext) {
         return Integer.valueOf(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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Max.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -28,6 +28,7 @@
 import org.teiid.api.exception.query.FunctionExecutionException;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.query.sql.symbol.Constant;
+import org.teiid.query.util.CommandContext;
 
 
 /**
@@ -41,9 +42,9 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List, CommandContext, CommandContext)
      */
-    public void addInputDirect(Object value, List<?> tuple)
+    public void addInputDirect(Object value, List<?> tuple, CommandContext commandContext)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
 
         if(maxValue == null) {
@@ -58,9 +59,9 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult(CommandContext)
      */
-    public Object getResult() {
+    public Object getResult(CommandContext commandContext) {
         return this.maxValue;
     }
 

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Min.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -28,6 +28,7 @@
 import org.teiid.api.exception.query.FunctionExecutionException;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.query.sql.symbol.Constant;
+import org.teiid.query.util.CommandContext;
 
 
 /**
@@ -41,9 +42,9 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List, CommandContext, CommandContext)
      */
-    public void addInputDirect(Object value, List<?> tuple)
+    public void addInputDirect(Object value, List<?> tuple, CommandContext commandContext)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
 
         if(minValue == null) {
@@ -58,9 +59,9 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult(CommandContext)
      */
-    public Object getResult() {
+    public Object getResult(CommandContext commandContext) {
         return this.minValue;
     }
 

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/RankingFunction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/RankingFunction.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/RankingFunction.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -28,6 +28,7 @@
 import org.teiid.api.exception.query.FunctionExecutionException;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.query.sql.symbol.AggregateSymbol.Type;
+import org.teiid.query.util.CommandContext;
 
 /**
  * computes rank/dense_rank
@@ -49,7 +50,7 @@
 	}
 	
 	@Override
-	public void addInputDirect(List<?> tuple)
+	public void addInputDirect(List<?> tuple, CommandContext commandContext)
 			throws FunctionExecutionException, ExpressionEvaluationException,
 			TeiidComponentException {
 		if (type == Type.RANK) {
@@ -58,7 +59,7 @@
 	}
 	
 	@Override
-	public Object getResult() throws FunctionExecutionException,
+	public Object getResult(CommandContext commandContext) throws FunctionExecutionException,
 			ExpressionEvaluationException, TeiidComponentException {
 		if (type == Type.DENSE_RANK) {
 			count++;

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/SingleArgumentAggregateFunction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/SingleArgumentAggregateFunction.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/SingleArgumentAggregateFunction.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -26,13 +26,14 @@
 
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
+import org.teiid.query.util.CommandContext;
 
 public abstract class SingleArgumentAggregateFunction extends AggregateFunction {
 
 	@Override
-	public void addInputDirect(List<?> tuple)
+	public void addInputDirect(List<?> tuple, CommandContext commandContext)
 			throws TeiidComponentException, TeiidProcessingException {
-		addInputDirect(tuple.get(argIndexes[0]), tuple);
+		addInputDirect(tuple.get(argIndexes[0]), tuple, commandContext);
 	}
 	
 	public void initialize(java.lang.Class<?> dataType, java.lang.Class<?>[] inputTypes) {
@@ -47,6 +48,6 @@
 		
 	}
 	
-	public abstract void addInputDirect(Object input, List<?> tuple)
+	public abstract void addInputDirect(Object input, List<?> tuple, CommandContext commandContext)
     throws TeiidProcessingException, TeiidComponentException;
 }

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/StatsFunction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/StatsFunction.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/StatsFunction.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -28,6 +28,7 @@
 import org.teiid.api.exception.query.FunctionExecutionException;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.query.sql.symbol.AggregateSymbol.Type;
+import org.teiid.query.util.CommandContext;
 
 public class StatsFunction extends SingleArgumentAggregateFunction {
 	
@@ -48,7 +49,7 @@
 	}
 	
 	@Override
-	public void addInputDirect(Object input, List<?> tuple)
+	public void addInputDirect(Object input, List<?> tuple, CommandContext commandContext)
 			throws FunctionExecutionException, ExpressionEvaluationException,
 			TeiidComponentException {
 		sum += ((Number)input).doubleValue();
@@ -57,7 +58,7 @@
 	}
 	
 	@Override
-	public Object getResult() throws FunctionExecutionException,
+	public Object getResult(CommandContext commandContext) throws FunctionExecutionException,
 			ExpressionEvaluationException, TeiidComponentException {
 		double result = 0;
 		switch (type) {

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/Sum.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -30,6 +30,7 @@
 import org.teiid.api.exception.query.FunctionExecutionException;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.types.DataTypeManager;
+import org.teiid.query.util.CommandContext;
 
 
 /**
@@ -85,9 +86,9 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List, CommandContext, CommandContext)
      */
-    public void addInputDirect(Object input, List<?> tuple)
+    public void addInputDirect(Object input, List<?> tuple, CommandContext commandContext)
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
         
     	isNull = false;
@@ -117,9 +118,9 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult(CommandContext)
      */
-    public Object getResult() 
+    public Object getResult(CommandContext commandContext) 
         throws FunctionExecutionException, ExpressionEvaluationException, TeiidComponentException {
         
     	if (isNull){

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -50,15 +50,13 @@
 public class TextAgg extends SingleArgumentAggregateFunction {
 
     private FileStoreInputStreamFactory result;
-    private CommandContext context;
     private TextLine textLine;
     
-    public TextAgg(CommandContext context, TextLine textLine) {
-    	this.context = context;
+    public TextAgg(TextLine textLine) {
     	this.textLine = textLine;    	    	
 	}
 
-	private FileStoreInputStreamFactory buildResult() throws TeiidProcessingException {
+	private FileStoreInputStreamFactory buildResult(CommandContext context) throws TeiidProcessingException {
 		try {
 			FileStore fs = context.getBufferManager().createFileStore("textagg"); //$NON-NLS-1$
 			FileStoreInputStreamFactory fisf = new FileStoreInputStreamFactory(fs, textLine.getEncoding()==null?Streamable.ENCODING:textLine.getEncoding());
@@ -87,12 +85,12 @@
     /**
      * @throws TeiidProcessingException 
      * @throws TeiidComponentException 
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List, CommandContext, CommandContext)
      */
-    public void addInputDirect(Object input, List<?> tuple) throws TeiidComponentException, TeiidProcessingException {
+    public void addInputDirect(Object input, List<?> tuple, CommandContext commandContext) throws TeiidComponentException, TeiidProcessingException {
     	try {
     		if (this.result == null) {
-    			this.result = buildResult();
+    			this.result = buildResult(commandContext);
     		}
     		String in = (String)input;
     		Writer w = result.getWriter();
@@ -104,11 +102,11 @@
     }
 
     /**
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult(CommandContext)
      */
-    public Object getResult() throws TeiidProcessingException{
+    public Object getResult(CommandContext commandContext) throws TeiidProcessingException{
     	if (this.result == null) {
-    		this.result = buildResult();
+    		this.result = buildResult(commandContext);
     	}
     	
     	try {

Added: trunk/engine/src/main/java/org/teiid/query/function/aggregate/UserDefined.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/UserDefined.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/UserDefined.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -0,0 +1,73 @@
+/*
+ * 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.UserDefinedAggregate;
+import org.teiid.api.exception.query.ExpressionEvaluationException;
+import org.teiid.api.exception.query.FunctionExecutionException;
+import org.teiid.core.TeiidComponentException;
+import org.teiid.core.TeiidProcessingException;
+import org.teiid.query.function.FunctionDescriptor;
+import org.teiid.query.util.CommandContext;
+
+public class UserDefined extends AggregateFunction {
+	
+	private FunctionDescriptor fd;
+	private UserDefinedAggregate<?> instance;
+	private Object[] values;
+	
+	public UserDefined(FunctionDescriptor functionDescriptor) {
+		this.fd = functionDescriptor;
+		this.instance = (UserDefinedAggregate<?>) fd.newInstance();
+	}
+
+	@Override
+	public void addInputDirect(List<?> tuple, CommandContext commandContext) throws TeiidComponentException,
+			TeiidProcessingException {
+		if (values == null) {
+			values = new Object[argIndexes.length + (fd.requiresContext()?1:0)];
+		}
+		if (fd.requiresContext()) {
+			values[0] = commandContext;
+		}
+		for (int i = 0; i < argIndexes.length; i++) {
+			values[i + (fd.requiresContext()?1:0)] = tuple.get(argIndexes[i]);
+		}
+		fd.invokeFunction(values, commandContext, instance);
+	}
+	
+	@Override
+	public void reset() {
+		instance.reset();
+	}
+	
+	@Override
+	public Object getResult(CommandContext commandContext) throws FunctionExecutionException,
+			ExpressionEvaluationException, TeiidComponentException,
+			TeiidProcessingException {
+		return instance.getResult(commandContext);
+	}
+	
+}


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

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/XMLAgg.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/XMLAgg.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/XMLAgg.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -37,10 +37,8 @@
 
 	private XMLType result;
 	private XmlConcat concat;
-    private CommandContext context;
     
-    public XMLAgg(CommandContext context) {
-    	this.context = context;
+    public XMLAgg() {
 	}
 
     public void reset() {
@@ -51,11 +49,11 @@
     /**
      * @throws TeiidProcessingException 
      * @throws TeiidComponentException 
-     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List)
+     * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(List, CommandContext, CommandContext)
      */
-    public void addInputDirect(Object input, List<?> tuple) throws TeiidComponentException, TeiidProcessingException {
+    public void addInputDirect(Object input, List<?> tuple, CommandContext commandContext) throws TeiidComponentException, TeiidProcessingException {
     	if (concat == null) {
-    		concat = new XmlConcat(context.getBufferManager());
+    		concat = new XmlConcat(commandContext.getBufferManager());
     	}
     	concat.addValue(input);
     }
@@ -63,9 +61,9 @@
     /**
      * @throws TeiidProcessingException 
      * @throws TeiidComponentException 
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult(CommandContext)
      */
-    public Object getResult() throws TeiidComponentException, TeiidProcessingException {
+    public Object getResult(CommandContext commandContext) throws TeiidComponentException, TeiidProcessingException {
     	if (result == null) {
     		if (concat == null) {
         		return null;

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/AccessNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/AccessNode.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/AccessNode.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -178,7 +178,7 @@
 		int i = 0;
 		int j = 0;
 		for (Iterator<Expression> iter = symbols.iterator(); iter.hasNext(); ) {
-			Expression ss = (Expression) iter.next();
+			Expression ss = iter.next();
 			Expression ex = SymbolMap.getExpression(ss);
 			if (ex instanceof Constant) {
 				projection[i] = ex;
@@ -208,7 +208,7 @@
 				Integer index = uniqueSymbols.get(SymbolMap.getExpression(item.getSymbol()));
 				if (index != null) {
 					item.setExpressionPosition(index);
-					item.setSymbol((Expression) select.getSymbols().get(index));
+					item.setSymbol(select.getSymbols().get(index));
 				}
 			}
 		}

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -184,7 +184,7 @@
             Class<?> outputType = symbol.getType();
             if(symbol instanceof AggregateSymbol) {
             	AggregateSymbol aggSymbol = (AggregateSymbol) symbol;
-            	functions[i] = initAccumulator(context, aggSymbol, this, this.collectedExpressions);
+            	functions[i] = initAccumulator(aggSymbol, this, this.collectedExpressions);
             } else {
                 functions[i] = new ConstantFunction();
                 functions[i].setArgIndexes(new int[] {this.collectedExpressions.get(symbol)});
@@ -202,8 +202,8 @@
 		return index;
 	}
 
-	static AggregateFunction initAccumulator(CommandContext context, 
-			AggregateSymbol aggSymbol, RelationalNode node, LinkedHashMap<Expression, Integer> expressionIndexes) {
+	static AggregateFunction initAccumulator(AggregateSymbol aggSymbol, 
+			RelationalNode node, LinkedHashMap<Expression, Integer> expressionIndexes) {
 		int[] argIndexes = new int[aggSymbol.getArgs().length];
 		AggregateFunction result = null;
 		Expression[] args = aggSymbol.getArgs();
@@ -235,14 +235,16 @@
 			result = new Max();
 			break;
 		case XMLAGG:
-			result = new XMLAgg(context);
+			result = new XMLAgg();
 			break;
 		case ARRAY_AGG:
-			result = new ArrayAgg(context);
+			result = new ArrayAgg();
 			break;                		
 		case TEXTAGG:
-			result = new TextAgg(context, (TextLine)args[0]);
-			break;                		
+			result = new TextAgg((TextLine)args[0]);
+			break;     
+		case USER_DEFINED:
+			result = new UserDefined(aggSymbol.getFunctionDescriptor());
 		default:
 			result = new StatsFunction(function);
 		}
@@ -382,7 +384,7 @@
                 // Close old group
                 List<Object> row = new ArrayList<Object>(functions.length);
                 for(int i=0; i<functions.length; i++) {
-                    row.add( functions[i].getResult() );
+                    row.add( functions[i].getResult(getContext()) );
                     functions[i].reset();
                 }
 
@@ -404,7 +406,7 @@
             // Close last group
             List<Object> row = new ArrayList<Object>(functions.length);
             for(int i=0; i<functions.length; i++) {
-                row.add( functions[i].getResult() );
+                row.add( functions[i].getResult(getContext()) );
             }
             
             addBatchRow(row);
@@ -425,7 +427,7 @@
     throws TeiidComponentException, TeiidProcessingException {
 
         for(int i=0; i<functions.length; i++) {
-            functions[i].addInput(tuple);
+            functions[i].addInput(tuple, getContext());
         }
     }
 

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/SortingFilter.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -35,6 +35,7 @@
 import org.teiid.query.processor.relational.SortUtility.Mode;
 import org.teiid.query.sql.lang.OrderByItem;
 import org.teiid.query.sql.symbol.ElementSymbol;
+import org.teiid.query.util.CommandContext;
 
 /**
  */
@@ -97,7 +98,7 @@
 	}
 	
 	@Override
-	public void addInputDirect(List<?> tuple)
+	public void addInputDirect(List<?> tuple, CommandContext commandContext)
 			throws TeiidComponentException, TeiidProcessingException {
         if(collectionBuffer == null) {
             collectionBuffer = mgr.createTupleBuffer(elements, groupName, TupleSourceType.PROCESSOR);
@@ -113,9 +114,9 @@
 	
     /**
      * @throws TeiidProcessingException 
-     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+     * @see org.teiid.query.function.aggregate.AggregateFunction#getResult(CommandContext)
      */
-    public Object getResult()
+    public Object getResult(CommandContext commandContext)
         throws TeiidComponentException, TeiidProcessingException {
 
         if(collectionBuffer != null) {
@@ -136,7 +137,7 @@
 	                    break;
 	                }
 	                //TODO should possibly remove the order by columns from this tuple
-	                this.proxy.addInputDirect(tuple);
+	                this.proxy.addInputDirect(tuple, commandContext);
 	            }
             } finally {
             	sorted.remove();
@@ -146,7 +147,7 @@
         }
 
         // Return
-        return this.proxy.getResult();
+        return this.proxy.getResult(commandContext);
     }
     
     @Override

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/WindowFunctionProjectNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/WindowFunctionProjectNode.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/WindowFunctionProjectNode.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -350,10 +350,10 @@
 				    }
 		        }
 		        for (AggregateFunction function : aggs) {
-		        	function.addInput(tuple);
+		        	function.addInput(tuple, getContext());
 		        }
 		        for (AggregateFunction function : rowValueAggs) {
-		        	function.addInput(tuple);
+		        	function.addInput(tuple, getContext());
 		        }
 		        lastRow = tuple;
 			}
@@ -375,7 +375,7 @@
 		List<Object> row = new ArrayList<Object>(aggs.size() + 1);
 		row.add(id);
 		for (AggregateFunction function : aggs) {
-			row.add(function.getResult());
+			row.add(function.getResult(getContext()));
 			if (!samePartition) {
 				function.reset();
 			}
@@ -400,7 +400,7 @@
 		}
 		List<ElementSymbol> elements = new ArrayList<ElementSymbol>(functions.size());
 		for (WindowFunctionInfo wfi : functions) {
-			aggs.add(GroupingNode.initAccumulator(this.getContext(), wfi.function.getFunction(), this, expressionIndexes));
+			aggs.add(GroupingNode.initAccumulator(wfi.function.getFunction(), this, expressionIndexes));
 			Class<?> outputType = wfi.function.getType();
 		    ElementSymbol value = new ElementSymbol("val"); //$NON-NLS-1$
 		    value.setType(outputType);
@@ -466,8 +466,10 @@
 	public void initialize(CommandContext context, BufferManager bufferManager,
 			ProcessorDataManager dataMgr) {
 		super.initialize(context, bufferManager, dataMgr);
-		List<? extends Expression> sourceElements = this.getChildren()[0].getElements();
-        this.elementMap = createLookupMap(sourceElements);
+		if (this.elementMap == null) {
+			List<? extends Expression> sourceElements = this.getChildren()[0].getElements();
+			this.elementMap = createLookupMap(sourceElements);
+		}
 	}
     
 }

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverVisitor.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -51,6 +51,7 @@
 import org.teiid.query.sql.lang.*;
 import org.teiid.query.sql.navigator.PostOrderNavigator;
 import org.teiid.query.sql.symbol.*;
+import org.teiid.query.sql.symbol.AggregateSymbol.Type;
 import org.teiid.query.sql.symbol.ElementSymbol.DisplayMode;
 
 
@@ -395,6 +396,9 @@
 				handleException(e);
 			}
     	}
+    	if (obj.getAggregateFunction() == Type.USER_DEFINED) {
+    		visit((Function)obj);
+    	}
     }
 
     public TeiidComponentException getComponentException() {

Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -1352,7 +1352,7 @@
         if (rightExpr instanceof Constant) {
             Constant const2 = (Constant)rightExpr;
             try {
-                Object result = descriptor.invokeFunction(new Object[] { const2.getValue(), const1.getValue() } );
+                Object result = descriptor.invokeFunction(new Object[] { const2.getValue(), const1.getValue() }, null, this.context );
                 combinedConst = new Constant(result, descriptor.getReturnType());
             } catch(FunctionExecutionException e) {
             	 throw new QueryValidatorException(QueryPlugin.Event.TEIID30373, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30373, e.getMessage()));
@@ -1590,9 +1590,9 @@
         }
     	Object value = ((Constant)rightExpr).getValue();
     	try {
-    		Object result = descriptor.invokeFunction(new Object[] {context, ((Constant)rightExpr).getValue(), format});
-    		result = leftFunction.getFunctionDescriptor().invokeFunction(new Object[] {context, result, format } );
-    		if (((Comparable)value).compareTo(result) != 0) {
+    		Object result = descriptor.invokeFunction(new Object[] {context, ((Constant)rightExpr).getValue(), format}, null, this.context );
+    		result = leftFunction.getFunctionDescriptor().invokeFunction(new Object[] {context, result, format }, null, this.context );
+    		if (Constant.COMPARATOR.compare(value, result) != 0) {
     			return getSimpliedCriteria(crit, leftExpr, crit.getOperator() != CompareCriteria.EQ, true);
     		}
     	} catch(FunctionExecutionException e) {

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/Query.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/Query.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/Query.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -454,6 +454,6 @@
     public boolean hasAggregates() {
     	return getGroupBy() != null 
     	|| getHaving() != null 
-    	|| !AggregateSymbolCollectorVisitor.getAllAggregates(getSelect()).isEmpty();
+    	|| !AggregateSymbolCollectorVisitor.getAggregates(getSelect(), false).isEmpty();
     }
 }  // END CLASS

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -132,12 +132,17 @@
 	 * @param expression Contained expression
 	 */
 	public AggregateSymbol(String aggregateFunction, boolean isDistinct, Expression expression) {
-		super(aggregateFunction, expression == null?EMPTY_ARGS:new Expression[] {expression});
+		this(aggregateFunction, isDistinct, expression == null?EMPTY_ARGS:new Expression[] {expression}, null);
+	}
+    
+	public AggregateSymbol(String aggregateFunction, boolean isDistinct, Expression[] args, OrderBy orderBy) {
+		super(aggregateFunction, args);
 		this.aggregate = nameMap.get(aggregateFunction);
 		if (this.aggregate == null) {
 			this.aggregate = Type.USER_DEFINED;
 		}
 		this.distinct = isDistinct;
+		this.orderBy = orderBy;
 	}
 	
 	/**

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -33,7 +33,6 @@
 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.Function;
 import org.teiid.query.sql.symbol.WindowFunction;
 
 
@@ -72,7 +71,6 @@
     private Collection<? super AggregateSymbol> aggregates;
     private Collection<? super ElementSymbol> otherElements;
     private Collection<? super WindowFunction> windowFunctions;
-	private Collection<? super Function> aggregateFunctions;
     
 	public AggregateSymbolCollectorVisitor(Collection<? super AggregateSymbol> aggregates, Collection<? super ElementSymbol> elements) { 
         this.aggregates = aggregates;
@@ -85,13 +83,6 @@
         }
     }
     
-    @Override
-    public void visit(Function obj) {
-    	if (aggregateFunctions != null && obj.isAggregate()) {
-            this.aggregateFunctions.add(obj);
-        }
-    }
-    
     public void visit(WindowFunction windowFunction) {
     	if (this.windowFunctions != null) {
     		this.windowFunctions.add(windowFunction);
@@ -116,18 +107,6 @@
         asn.visitNode(obj);
     }
 
-    public static final Collection<Function> getAllAggregates(LanguageObject obj) {
-    	if (obj == null) {
-    		return Collections.emptyList();
-    	}
-        Collection<Function> aggregates = new ArrayList<Function>();    
-        AggregateSymbolCollectorVisitor visitor = new AggregateSymbolCollectorVisitor(aggregates, null);
-        visitor.aggregateFunctions = aggregates;
-        AggregateStopNavigator asn = new AggregateStopNavigator(visitor, null, null);
-        obj.acceptVisitor(asn);
-        return aggregates;
-    }
-    
     public static final Collection<AggregateSymbol> getAggregates(LanguageObject obj, boolean removeDuplicates) {
     	if (obj == null) {
     		return Collections.emptyList();

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -1074,12 +1074,15 @@
     // ############ Visitor methods for symbol objects ####################
 
     public void visit( AggregateSymbol obj ) {
-        append(obj.getAggregateFunction().name());
+        append(obj.getName());
         append("("); //$NON-NLS-1$
 
         if (obj.isDistinct()) {
             append(DISTINCT);
             append(" "); //$NON-NLS-1$
+        } else if (obj.getAggregateFunction() == Type.USER_DEFINED) {
+        	append(ALL);
+        	append(" "); //$NON-NLS-1$
         }
 
         if (obj.getArgs().length == 0) {

Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -44,6 +44,7 @@
 import org.teiid.core.TeiidProcessingException;
 import org.teiid.core.types.DataTypeManager;
 import org.teiid.core.util.EquivalenceUtil;
+import org.teiid.metadata.AggregateAttributes;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.eval.Evaluator;
 import org.teiid.query.function.FunctionLibrary;
@@ -324,6 +325,8 @@
         	} catch (IllegalArgumentException e) {
         		handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.invalid_encoding", obj.getArg(1)), obj); //$NON-NLS-1$
         	}
+        } else if (obj.isAggregate()) {
+        	handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.user_defined_aggregate_as_function", obj, obj.getName()), obj); //$NON-NLS-1$
         }
     }
 
@@ -983,6 +986,18 @@
     		handleValidationError(QueryPlugin.Util.getString("SQLParser.Aggregate_only_top_level", obj), obj); //$NON-NLS-1$
     		return;
     	}
+    	if (obj.getAggregateFunction() == AggregateSymbol.Type.USER_DEFINED) {
+    		AggregateAttributes aa = obj.getFunctionDescriptor().getMethod().getAggregateAttributes();
+    		if (!aa.allowsDistinct() && obj.isDistinct()) {
+    			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.uda_not_allowed", "DISTINCT", obj), obj); //$NON-NLS-1$ //$NON-NLS-2$
+    		}
+    		if (!aa.allowsOrderBy() && obj.getOrderBy() != null) {
+    			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.uda_not_allowed", "ORDER BY", obj), obj); //$NON-NLS-1$ //$NON-NLS-2$
+    		}
+    		if (!aa.isWindowable() && obj.isWindowed()) {
+    			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.uda_not_allowed", "windowing", obj), obj); //$NON-NLS-1$ //$NON-NLS-2$ 
+    		}
+    	}
     	if (obj.getCondition() != null) {
     		Expression condition = obj.getCondition();
     		validateNoSubqueriesOrOuterReferences(condition);

Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2012-04-04 19:54:58 UTC (rev 3973)
@@ -3326,7 +3326,7 @@
 		(expression=aggregateSymbol(info) expression = windowSpecification(expression, info))
 		|
 		// Function
-		LOOKAHEAD(2) (expression=function(info))
+		LOOKAHEAD(2) (expression=function(info) [expression = windowSpecification(expression, info)])
 		|
 		// ElementSymbol
 		(symbol=<ID> 
@@ -3389,6 +3389,9 @@
     {
     	WindowFunction result = new WindowFunction();
     	WindowSpecification ws = new WindowSpecification();
+    	if (!(agg instanceof AggregateSymbol)) {
+	   		throw new ParseException(QueryPlugin.Util.getString("SQLParser.invalid_window", agg)); //$NON-NLS-1$
+    	}
     	result.setFunction((AggregateSymbol)agg);
     	ws.setPartition(partitionList);
     	ws.setOrderBy(orderBy);
@@ -3477,6 +3480,9 @@
 	ArrayList args = new ArrayList(2);
 	ArrayList otherArgs = null;
 	Token funcToken = null;
+	Boolean distinct = null;
+	OrderBy orderBy = null;
+	Expression condition = null;
 }
 {
 	((	funcToken = <CONVERT>
@@ -3681,14 +3687,21 @@
 	|   
 	(	funcName = id()
 		<LPAREN>
+		[<ALL> { distinct = false; } | <DISTINCT> {distinct = true;} ]
 		[ args = expressionList(info) ]
+		[ orderBy = orderby(info) ]
 		<RPAREN>
+		condition = filterClause(info)
 	))		
 	{
 		if(funcName == null) { 
 			funcName = funcToken.image;
 		}
-			
+		if (distinct != null || orderBy != null || condition != null) {
+			AggregateSymbol as = new AggregateSymbol(funcName, distinct, (Expression[])args.toArray(new Expression[args.size()]), orderBy);
+			as.setCondition(condition);
+			return as;
+		}	
 		return new Function(funcName, (Expression[])args.toArray(new Expression[args.size()]));
 	}
 }

Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2012-04-04 19:54:58 UTC (rev 3973)
@@ -274,6 +274,7 @@
 SQLParser.Invalid_short_name=Invalid simple identifier format: [{0}]
 SQLParser.Invalid_char={0} value must be a single character: [{1}].
 SQLParser.expected_non_reserved=Expected non-reserved word {0}, but was {1}.
+SQLParser.invalid_window=Cannot window a non-aggregate expression {0}.
 SystemSource.array_length_desc=Get the length of the given array value
 SystemSource.array_param1=Array
 SystemSource.array_length_result=The array length
@@ -673,6 +674,8 @@
 ValidationVisitor.badlimit2=The row limit in the LIMIT clause must be >= 0
 ValidationVisitor.invalid_scalar_group_reference=Cannot reference a scalar group as a table: {0}
 ValidationVisitor.select_into_wrong_elements=Wrong number of elements being SELECTed INTO the target table. Expected {0} elements, but was {1}.
+ValidationVisitor.user_defined_aggregate_as_function=Cannot call user defined aggregate function {0} as a function.  To disambiguate, please include an ALL keyword - {1}(ALL ...)
+ValidationVisitor.uda_not_allowed=User defined aggregate function does not allow {0}: {1}
 SimpleQueryResolver.Query_was_redirected_to_Mat_table=The query against {0} was redirected to the materialization table {1}.
 SimpleQueryResolver.ambiguous_all_in_group=The symbol {0} refers to more than one group defined in the FROM clause.
 TEIID30114=Cannot access procedure {0} using table semantics since the parameter and result set column names are not all unique.
@@ -1060,4 +1063,5 @@
 
 TEIID30600=User defined aggregate function "{0}" method "{1}" must not be static.
 TEIID30601=User defined aggregate function "{0}" class "{1}" does not implement {2}
+TEIID30602=User defined aggregate function "{0}" class "{1}" does not provide a public no-arg constructor.
 

Modified: trunk/engine/src/test/java/org/teiid/query/function/TestFunctionLibrary.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/function/TestFunctionLibrary.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/test/java/org/teiid/query/function/TestFunctionLibrary.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -227,11 +227,11 @@
             for (int i = 0; i < inputs.length; i++) {
                 in[i+1] = inputs[i];
             }
-            actualOutput = descriptor.invokeFunction(in);
+            actualOutput = descriptor.invokeFunction(in, null, null);
         }
         else {
             // Invoke function with inputs
-            actualOutput = descriptor.invokeFunction(inputs);                
+            actualOutput = descriptor.invokeFunction(inputs, null, null);                
         }
 		return actualOutput;
 	}

Modified: trunk/engine/src/test/java/org/teiid/query/function/TestFunctionTree.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/function/TestFunctionTree.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/test/java/org/teiid/query/function/TestFunctionTree.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -162,7 +162,7 @@
     	FunctionLibrary fl = new FunctionLibrary(sys, new FunctionTree("foo", new UDFSource(Arrays.asList(method)), true));
     	FunctionDescriptor fd = fl.findFunction("dummy", new Class<?>[] {DataTypeManager.DefaultDataClasses.VARBINARY});
     	String hello = "hello";
-    	assertEquals(hello, fd.invokeFunction(new Object[] {new BinaryType(hello.getBytes())}));
+    	assertEquals(hello, fd.invokeFunction(new Object[] {new BinaryType(hello.getBytes())}, null, null));
     }
 	
 /*

Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -5213,5 +5213,19 @@
 		assertEquals(DataTypeManager.DefaultDataClasses.VARBINARY, actualCommand.getSelect().getSymbol(0).getType());
 		assertEquals("SELECT X'AABBCC0A'", actualCommand.toString());
     }
+    
+    @Test public void testUserDefinedAggregateParsing() throws QueryParserException {
+		Query actualCommand = (Query)QueryParser.getQueryParser().parseCommand("SELECT foo(ALL x, y)", new ParseInfo());
+		assertEquals("SELECT foo(ALL x, y)", actualCommand.toString());
+    }
 
+    @Test(expected=QueryParserException.class) public void testWindowedExpression() throws QueryParserException {
+		QueryParser.getQueryParser().parseCommand("SELECT foo(x, y) over ()", new ParseInfo());
+    }
+    
+    @Test public void testWindowedExpression1() throws QueryParserException {
+		Query actualCommand = (Query)QueryParser.getQueryParser().parseCommand("SELECT foo(distinct x, y) over ()", new ParseInfo());
+		assertEquals("SELECT foo(DISTINCT x, y) OVER ()", actualCommand.toString());
+    }
+
 }

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	2012-04-04 19:49:28 UTC (rev 3972)
+++ trunk/engine/src/test/java/org/teiid/query/processor/relational/TestDuplicateFilter.java	2012-04-04 19:54:58 UTC (rev 3973)
@@ -52,10 +52,10 @@
         
         // Add inputs
         for(int i=0; i<input.length; i++) {
-            filter.addInputDirect(Arrays.asList(input[i]));    
+            filter.addInputDirect(Arrays.asList(input[i]), null);    
         }        
         
-        Integer actual = (Integer) filter.getResult();
+        Integer actual = (Integer) filter.getResult(null);
         assertEquals("Did not get expected number of results", expected, actual.intValue()); //$NON-NLS-1$
     }
 



More information about the teiid-commits mailing list