db-torque-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gmon...@apache.org
Subject svn commit: r643209 - in /db/torque: runtime/trunk/src/java/org/apache/torque/adapter/ runtime/trunk/src/java/org/apache/torque/util/ runtime/trunk/src/java/org/apache/torque/util/functions/ test/trunk/test-project/src/java/org/apache/torque/util/ test...
Date Mon, 31 Mar 2008 23:33:44 GMT
Author: gmonroe
Date: Mon Mar 31 16:33:41 2008
New Revision: 643209

URL: http://svn.apache.org/viewvc?rev=643209&view=rev
Log:
Support for DB Adaptor specific SQL functions and the SummaryHelper class which supports getting results from aggregate queries.  E.g. Select Sum(x) from table.

Added:
    db/torque/runtime/trunk/src/java/org/apache/torque/util/SummaryHelper.java
    db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/
    db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/AbstractFunction.java
    db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/Aggregate.java
    db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionEnum.java
    db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionFactory.java
    db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/SQLFunction.java
    db/torque/test/trunk/test-project/src/java/org/apache/torque/util/SummaryHelperTest.java
Modified:
    db/torque/runtime/trunk/src/java/org/apache/torque/adapter/AbstractDBAdapter.java
    db/torque/runtime/trunk/src/java/org/apache/torque/adapter/DB.java
    db/torque/test/trunk/test-project/src/schema/test-schema.xml

Modified: db/torque/runtime/trunk/src/java/org/apache/torque/adapter/AbstractDBAdapter.java
URL: http://svn.apache.org/viewvc/db/torque/runtime/trunk/src/java/org/apache/torque/adapter/AbstractDBAdapter.java?rev=643209&r1=643208&r2=643209&view=diff
==============================================================================
--- db/torque/runtime/trunk/src/java/org/apache/torque/adapter/AbstractDBAdapter.java (original)
+++ db/torque/runtime/trunk/src/java/org/apache/torque/adapter/AbstractDBAdapter.java Mon Mar 31 16:33:41 2008
@@ -23,9 +23,13 @@
 import java.sql.SQLException;
 import java.sql.Timestamp;
 import java.util.Date;
+import java.util.Hashtable;
+import java.util.Map;
 
 import org.apache.torque.TorqueException;
 import org.apache.torque.util.Query;
+import org.apache.torque.util.functions.Aggregate;
+import org.apache.torque.util.functions.FunctionEnum;
 
 /**
  * This class is the abstract base for any database adapter
@@ -56,10 +60,32 @@
  * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
  * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
  * @author <a href="mailto:vido@ldh.org">Augustin Vidovic</a>
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
  * @version $Id: DB.java 393063 2006-04-10 20:59:16Z tfischer $
  */
 public abstract class AbstractDBAdapter implements DB
 {
+    /** 
+     * The default look up table for function classes.
+     */
+    private Map functionClasses = new Hashtable(10);
+    /*
+     * Initialize the functionClasses lookup table with SQL99 standard
+     * functions. Uses this method because DB implementations don't 
+     * currently call super() in their constructors and we want this
+     * to be set in all of them.
+     * 
+     * Override the values set here in the DB Specific adaptor's
+     * constructor.
+     */
+    {
+        functionClasses.put( FunctionEnum.AVG, Aggregate.Avg.class );
+        functionClasses.put( FunctionEnum.COUNT, Aggregate.Count.class );
+        functionClasses.put( FunctionEnum.MAX, Aggregate.Max.class );
+        functionClasses.put( FunctionEnum.MIN, Aggregate.Min.class );
+        functionClasses.put( FunctionEnum.SUM, Aggregate.Sum.class );
+    }
+    
     /**
      * Empty constructor.
      */
@@ -278,4 +304,19 @@
     {
         return false;
     }
+
+    /**
+     * Return the class which implements the SQLFunction interface for the
+     * specified function.
+     * 
+     * @param function The function to get the class for.
+     * @return The SQLFunction implementation for a function of this type that
+     *         will work with this type of DB. Null indicates a class was not
+     *         found. 
+     */
+    public Class getFunctionClass( FunctionEnum function ) 
+    {
+        return (Class) functionClasses.get( function );
+    }
+
 }

Modified: db/torque/runtime/trunk/src/java/org/apache/torque/adapter/DB.java
URL: http://svn.apache.org/viewvc/db/torque/runtime/trunk/src/java/org/apache/torque/adapter/DB.java?rev=643209&r1=643208&r2=643209&view=diff
==============================================================================
--- db/torque/runtime/trunk/src/java/org/apache/torque/adapter/DB.java (original)
+++ db/torque/runtime/trunk/src/java/org/apache/torque/adapter/DB.java Mon Mar 31 16:33:41 2008
@@ -26,6 +26,7 @@
 
 import org.apache.torque.TorqueException;
 import org.apache.torque.util.Query;
+import org.apache.torque.util.functions.FunctionEnum;
 
 /**
  * <code>DB</code> defines the interface for a Torque database
@@ -62,6 +63,7 @@
  * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
  * @author <a href="mailto:vido@ldh.org">Augustin Vidovic</a>
  * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
  * @version $Id$
  */
 public interface DB extends Serializable, IDMethod
@@ -268,4 +270,19 @@
      * @return whether the escape clause should be appended or not.
      */
     boolean useEscapeClauseForLike();
+    
+    /**
+     * Return the class which implements the SQLFunction interface for the
+     * specified function. This class must have an empty constructor and 
+     * can be a single level inner class (or not). 
+     * 
+     * @param function The function to get the class for.
+     * @return The SQLFunction implementation for a function of this type that
+     *         will work with this type of DB. Null indicates a class was not
+     *         found. 
+     * @see SQLFunction
+     * @see AbstractFunction
+     * @see Aggregate
+     */
+    Class getFunctionClass( FunctionEnum function );
 }

Added: db/torque/runtime/trunk/src/java/org/apache/torque/util/SummaryHelper.java
URL: http://svn.apache.org/viewvc/db/torque/runtime/trunk/src/java/org/apache/torque/util/SummaryHelper.java?rev=643209&view=auto
==============================================================================
--- db/torque/runtime/trunk/src/java/org/apache/torque/util/SummaryHelper.java (added)
+++ db/torque/runtime/trunk/src/java/org/apache/torque/util/SummaryHelper.java Mon Mar 31 16:33:41 2008
@@ -0,0 +1,406 @@
+package org.apache.torque.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+import java.sql.Connection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.commons.collections.OrderedMap;
+import org.apache.commons.collections.OrderedMapIterator;
+import org.apache.commons.collections.map.ListOrderedMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.torque.TorqueException;
+import org.apache.torque.util.functions.SQLFunction;
+
+import com.workingdogs.village.DataSetException;
+import com.workingdogs.village.Record;
+import com.workingdogs.village.Value;
+
+/**
+ * <p>A utility to help produce aggregate summary information about a table.
+ * The default assumes that the underlying DB supports the SQL 99 Standard
+ * Aggregate functions, e.g. COUNT, SUM, AVG, MAX, & MIN.  However, some
+ * non-standard functions (like MySQL's older LEAST instead of MIN can be 
+ * handled programatically if needed (@see Aggregate class)</p>
+ *   
+ * <P>Here is a simple example to generate the results of a query like:</P>
+ * 
+ * <pre>
+ * SELECT EMPLOYEE, SUM(HOURS), MIN(HOURS), MAX(HOURS) 
+ *     FROM TIMESHEET WHERE TYPE = 1 GROUP BY EMPLOYEE ORDER BY EMPLOYEE ASC
+ * </pre>
+ * <p>Use the following code</p>
+ * <pre>
+ *    SummaryHelper sHelp = new SummaryHelper();
+ *    Criteria c = new Criteria();
+ *    c.add(TimeSheetPeer.TYPE, 1);
+ *    c.addAscendingOrderBy(TimeSheetPeer.EMPLOYEE);
+ *    sHelper.addGroupBy(TimeSheetPeer.EMPLOYEE);
+ *    sHelper.addAggregate(FunctionFactory.Sum(TimeSheetPeer.HOURS),"Hours");
+ *    sHelper.addAggregate(FunctionFactory.Min(TimeSheetPeer.HOURS),"Min_Hrs");
+ *    sHelper.addAggregate(FunctionFactory.Max(TimeSheetPeer.HOURS),"Max_Hrs");
+ *    List results = sHelper.summarize( c );
+ * </pre>
+ * <p>The results list will be an OrderedMap with a key of either the group by
+ * column name or the name specified for the aggregate function (e.g. EMPLOYEE
+ * or Hours).  The value will be a Village Value Class.  Below is a simple
+ * way to do this.  See the dumpResults* method code for a more complex example.
+ * </p>
+ * <pre>
+ *    String emp = results.get("EMPLOYEE").asString();
+ *    int hours = results.get("Hours").asInt();
+ * </pre>
+ * <p>
+ * Notes:</p>
+ * <p>
+ * If there are no group by columns specified, the aggregate is over the
+ * whole table.  The from table is defined either via the Criteria.addAlias(...)
+ * method or by the first table prefix in an aggregate function.</p>
+ * <p>
+ * This will also work with joined tables if the criteria is creates as
+ * to create valid SQL.</p> 
+ *
+ * @see org.apache.torque.util.functions.FunctionFactory
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
+ * @version $Id
+ */
+public class SummaryHelper
+{
+    static Log logger = LogFactory.getLog(SummaryHelper.class);
+    
+    /** A list of the group by columns names (e.g. TABLE.COLUMN) */
+    private List groupByColumns;
+    /** A OrderMap<String,Aggregate.Function> with the aggregate functions
+     * to use in generating results. */
+    private OrderedMap aggregates;
+    /** Flag for excluding unnamed columns. */
+    private boolean excludeExprColumns = false;
+    
+    /**
+     * Simple constructor
+     */
+    public SummaryHelper() 
+    {
+        super();
+    }
+    
+    /**
+     * Return a list of OrderedMap objects with the results of the summary
+     * query.  The OrderedMap objects have a key of the column name or
+     * function alias and are in the order generated by the query.
+     * 
+     * @param crit The base criteria to build on.
+     * @return Results as a OrderMap<String,Values> object.  
+     * @throws TorqueException
+     * @throws DataSetException
+     */
+    public List summarize( Criteria crit ) 
+                                throws TorqueException, DataSetException 
+    {
+        return summarize( crit, null );
+    }
+    
+    /**
+     * Return a list of OrderedMap objects with the results of the summary
+     * query.  The OrderedMap objects have a key of the column name or
+     * function alias and are in the order generated by the query.
+     *
+     * @param crit The base criteria to build on.
+     * @param conn The DB Connection to use.
+     * @return Results as a OrderMap<String,Values> object. 
+     * @throws TorqueException
+     * @throws DataSetException
+     */
+    public List summarize( Criteria crit, Connection conn ) 
+                                 throws TorqueException, DataSetException 
+    {
+        Criteria c = buildCriteria( crit );
+         
+        List results;
+        if (conn == null)
+        {
+            results = BasePeer.doSelect(c);
+        }
+        else
+        {
+            results = BasePeer.doSelect(c, conn);
+        }
+
+        Iterator r = results.iterator();
+        
+        Vector resultsList = new Vector(results.size());
+        while ( r.hasNext() ) 
+        {
+            ListOrderedMap recordMap = new ListOrderedMap();
+            Record rec = (Record) r.next();
+            String cName = null;
+            Value value = null;
+            for ( int i = 1; i <= rec.size(); i++ ) 
+            {
+                value = rec.getValue(i);
+                cName = rec.schema().column(i).name();
+                if ( cName == null || cName.equals("") ) 
+                 {
+                    if ( excludeExprColumns() ) {
+                        continue;
+                    }
+                    cName = "Expr" + i;
+                }
+                recordMap.put(cName, value);
+            }
+            resultsList.add(recordMap);
+        }
+        return resultsList;  
+    }
+    
+    /**
+     * Builds the criteria to use in summarizing the information.  Note that
+     * the criteria passed in will be modified.
+     * 
+     * @param c The base criteria to build the summary criteria from.
+     * @return A criteria to use in summarizing the information.
+     * @throws TorqueException
+     */
+    public Criteria buildCriteria( Criteria c ) throws TorqueException {
+        
+        c.getSelectColumns().clear();
+        c.getGroupByColumns().clear();
+        
+        UniqueList criteriaSelectModifiers;
+        criteriaSelectModifiers = c.getSelectModifiers();
+
+        if (criteriaSelectModifiers != null
+            && criteriaSelectModifiers.size() > 0
+            && criteriaSelectModifiers.contains(SqlEnum.DISTINCT.toString()))
+        {
+            criteriaSelectModifiers.remove(SqlEnum.DISTINCT.toString());
+        }
+        c.setIgnoreCase(false);
+
+        List cols = null;
+        Iterator i = null;
+        
+        cols = getGroupByColumns();
+        i = cols.iterator();
+        boolean haveFromTable = i.hasNext(); // Group By cols define src table.
+        while ( i.hasNext() ) 
+        {
+            String col = (String) i.next();
+            c.addGroupByColumn( col );
+            c.addSelectColumn(col);
+        }
+        if ( haveFromTable ) 
+            logger.debug("From table defined by Group By Cols");
+        
+        // Check if the from table is set via a where clause.
+        if ( ! haveFromTable && c.keys().hasMoreElements() ) 
+        {
+            haveFromTable = true;
+            logger.debug("From table defined by a where clause");
+        }
+        
+        OrderedMap cMap = getAggregates();
+        OrderedMapIterator iMap = cMap.orderedMapIterator();
+        while ( iMap.hasNext() ) 
+        {
+            String key = (String) iMap.next();
+            SQLFunction f = (SQLFunction) iMap.getValue();
+            c.addAsColumn( key, f.toSQL() );
+            if ( ! haveFromTable )    // Last chance. Get it from the func.
+            {
+                String col =  f.getArgument(0).toString();
+                if ( col.contains(".") ) 
+                {
+                    // Kludgy Where table.col = table.col clause to force
+                    // from table identification.
+                    c.add( col,(Object)(col + "=" + col), SqlEnum.CUSTOM );  
+                    haveFromTable = true;
+
+                    String table = col.substring(0,col.indexOf('.'));
+                    logger.debug("From table, '" + table + 
+                                 "', defined from aggregate column");
+                }
+            }
+        }
+        if ( ! haveFromTable ) 
+        {
+            throw new TorqueException(
+                         "No FROM table defined by the GroupBy set, " +
+                         "criteria.setAlias, or specified function column!");
+        }
+        return c;
+    }
+
+    /**
+     * <p>
+     * Add a column that will be used to group the aggregate results by. 
+     * This is a first added / first listed on SQL method.  E.g.,
+     * </p>
+     * <pre> 
+     *    add(TablePeer.COL1); 
+     *    add(TablePeer.COL2);
+     * </pre>
+     *     
+     * <p>Generates SQL like:  SELECT .... GROUP BY Table.COL1, TABLE.COL2</p>
+     * 
+     * @param column
+     */
+    public void addGroupBy( String column ) 
+    {
+        getGroupByColumns().add(column);
+    }
+      
+    /**
+     * Add in an Aggregate function to the summary information.  
+     * 
+     * @param alias  A valid SQL99 column identifier ([_A-Z0-9] no spaces and 
+     *               no key words, e.g. function names.
+     * @param function One of the inner classes from the Aggregate class. 
+     */
+    public void addAggregate( String alias, SQLFunction function ) 
+    {
+        getAggregates().put( alias, function );
+    }
+    
+    /**
+     *  Resets the class internal variables to their initial states so
+     *  the class can be re-used like a new class. 
+     */
+    public void clear() 
+    {
+        getGroupByColumns().clear();
+        getAggregates().clear();
+        setExcludeExprColumns(false);
+    }
+
+    public List getGroupByColumns() 
+    {
+        if ( groupByColumns == null ) 
+        {
+            groupByColumns = new Vector();
+        }
+        return groupByColumns;
+    }
+
+    /**
+     * Get the order map list of aggregate functions to use in
+     * summarizing this table's informations.  The key is used
+     * as the result column alias.
+     * 
+     * @return the avgColumns.  Will always return a ListOrderedMap object.
+     */
+    public OrderedMap getAggregates()
+    {
+        if ( aggregates == null ) 
+        {
+            aggregates = new ListOrderedMap();
+        }
+        return aggregates;
+    }
+    
+    /**
+     * Convenience method to dump a summary results list to an output writer 
+     * in a semi-CSV format. E.g., there is no handling of embedded 
+     * quotes/special characters.
+     * 
+     * @param out
+     * @param results
+     * @param includeHeader
+     * @throws IOException
+     */
+    public void dumpResults(Writer out, List results, boolean includeHeader ) 
+                                                            throws IOException 
+    {
+        Iterator i = results.iterator();
+        boolean first = includeHeader;
+        
+        while ( i.hasNext() ) 
+        {
+            OrderedMap rec = (OrderedMap ) i.next();
+            OrderedMapIterator rI = rec.orderedMapIterator();
+            String heading = "";
+            String recString = "";
+            while ( rI.hasNext() ) 
+            {
+                String colId = (String) rI.next();
+                if ( first ) 
+                {
+                    heading += "\"" + colId + "\"";
+                    if ( rI.hasNext() ) 
+                    {
+                        heading += ", ";
+                    }
+                }
+                Value v = (Value) rI.getValue();
+                if ( v.isString() ) 
+                {
+                    recString += "\"" + v.toString() + "\"";
+                } 
+                else 
+                {
+                    recString += v.toString();
+                }
+                if ( rI.hasNext() ) 
+                {
+                    recString += ", ";
+                }
+            }
+            if ( first ) 
+            {
+                first = false;
+                out.write(heading);
+                out.write("\n");
+            }
+            out.write(recString);
+            out.write("\n");
+        }
+    }
+
+    /**
+     * Should the results include unnamed columns, e.g. EXPR{index#}. 
+     * 
+     * @return the excludeExprColumns
+     */
+    public boolean excludeExprColumns()
+    {
+        return excludeExprColumns;
+    }
+
+    /**
+     * <p>Define if unnamed output columns which get labeled as EXPR{index#}) 
+     * should be included in the the output set.</p>
+     * <p>  
+     * Note these are generally added by the criteria 
+     * processing to handle special cases such as case insensitive ordering.
+     * </p> 
+     * 
+     * @param excludeExprColumns if True, these columns won't be included.
+     */
+    public void setExcludeExprColumns(boolean excludeExprColumns)
+    {
+        this.excludeExprColumns = excludeExprColumns;
+    }
+    
+}

Added: db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/AbstractFunction.java
URL: http://svn.apache.org/viewvc/db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/AbstractFunction.java?rev=643209&view=auto
==============================================================================
--- db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/AbstractFunction.java (added)
+++ db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/AbstractFunction.java Mon Mar 31 16:33:41 2008
@@ -0,0 +1,161 @@
+package org.apache.torque.util.functions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.torque.Torque;
+
+/**
+ * A default framework that implements the core SQLFunction interface 
+ * requirements that can be used to build specific functions on. 
+ * 
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
+ * @version $Id
+ */
+public abstract class AbstractFunction implements SQLFunction
+{
+    /** The arguments being used by this function */
+    private List argumentList;
+    /** The Torque DB connector name this function is associated with */
+    private String dbName;
+    
+    /**
+     * Functions should only be created via the FunctionFactory class.
+     */
+    protected AbstractFunction() {
+        super();
+    }
+
+    /**
+     * This should return the SQL string that can be used
+     * when constructing the query.  E.g. "AVG( table.column )" or
+     * CONCAT(table.column, " foobar");
+     *  
+     * @return The SQL String.
+     */
+    public abstract String toSQL();
+
+    /**
+     * Return a string representation of the function parameter
+     * at the specified index.  Should be null if parameter does not exist.
+     * 
+     * @param index The 0 based index of the parameter to get.
+     * @return A String representation of the parameter.  Null if one does not
+     *         exist.
+     */
+    public abstract String getArgument( int i );
+    
+    /**
+     * Return all the parameters as an object array. This allow for 
+     * processing of the parameters in their original format rather
+     * than just in String format.  E.g. a parameter might be specified
+     * as a Date object, or a Column object.
+     * 
+     * @return Should return a valid Object array and not null.  E.g. 
+     *  implementors should return new Object[0] if there are no parameters.
+     */
+    public Object[] getArguments()
+    {
+        Object[] args = getArgumentList().toArray();
+        if ( args == null ) 
+        {
+            args = new Object[0];
+        }
+        return args;
+    }
+
+    /**
+     * Get the name of the Torque Database associated with this function.
+     * 
+     * @return The DB name.  Should not be null (use default DB in this case).
+     * @exception IllegalStateException If Torque has not been initialized and
+     *   the default DB name can not be determined.
+     */
+    public String getDBName() throws IllegalStateException
+    {
+        if ( this.dbName == null ) {
+            this.dbName = Torque.getDefaultDB(); 
+        }
+        if ( this.dbName == null ) {
+            throw new IllegalStateException(
+                 "Could not get DB Name!  Torque may not be initialized yet!");
+        }
+        return this.dbName;
+    }
+
+    /**
+     * Return the object representation of the function parameter
+     * at the specified index.  Will be null if parameter does not exist.
+     * 
+     * @param index The 0 based index of the parameter to get.
+     * @return The parameter object.  Null if one does not
+     *         exist.
+     */
+    protected Object getArgumentObject( int index )
+    {
+        List argList = getArgumentList();
+        if ( index >= argList.size() ) 
+        {
+            return null;
+        }
+        return argList.get(index);
+    }
+
+    /**
+     * Add an argument to the function argument list
+     * 
+     * @param arg The argument object.
+     */
+    protected void addArgument( Object arg ) {
+        getArgumentList().add( arg );
+    }
+
+    /**
+     * Set the full function argument list.
+     * 
+     * @param args The new argument list 
+     */
+    protected void setArgumentList( List args ) {
+        this.argumentList = args;
+    }
+    
+    /**
+     * Get the full list of function arguments
+     * 
+     * @return The argument list
+     */
+    protected List getArgumentList( ) {
+        if ( this.argumentList == null ) {
+            this.argumentList = new Vector();
+        }
+        return this.argumentList;
+    }
+    
+    /**
+     * @param dbName the dbName to set
+     */
+    public void setDBName(String dbName)
+    {
+        this.dbName = dbName;
+    }
+
+}

Added: db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/Aggregate.java
URL: http://svn.apache.org/viewvc/db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/Aggregate.java?rev=643209&view=auto
==============================================================================
--- db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/Aggregate.java (added)
+++ db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/Aggregate.java Mon Mar 31 16:33:41 2008
@@ -0,0 +1,257 @@
+package org.apache.torque.util.functions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.torque.adapter.DB;
+
+/**
+ * <p>A container for classes that will generate SQL for the SQL99 Standard 
+ * Aggregate functions. These can be used via the Criteria.addAsColumn
+ * method to produce SQL statements that can be called via the 
+ * BasePeer.doSelect methods.</p>  
+ * <p>
+ * Note database servers that use non-standard function names  
+ * can be supported by using the setFunction(String) method.</p>
+ * <p>
+ * E.g., older MySQL servers use LEAST instead of MIN. This can be 
+ * supported by creating a Aggregate.Min instance and then calling
+ * the setFunction("LEAST") method.</p>
+ * 
+ * @see org.apache.torque.util.SummaryHelper
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
+ * @version $Id
+ */
+public class Aggregate
+{
+
+    /**
+     * The base class for all the standard aggregate function classes.
+     */
+    public abstract class AgregateFunction 
+                        extends AbstractFunction 
+                        implements SQLFunction
+    {
+        /** Should the column have DISTINCT added before it */
+        private boolean distinct;
+        /** The function to use */
+        private String function;
+        /** Flag to determine if arguments have been set */
+        private boolean argumentsSet = false;
+        
+        /**
+         * Base constructor for aggregate functions which must be created
+         * via the FunctionFactory / DB classes.<p>  
+         * 
+         * @see FunctionFactory
+         * @see DB
+         */
+        protected AgregateFunction ( ) 
+        {
+            super();
+        }
+        
+       /**
+        * Assumes that there are one or two arguments being specified.  The
+        * first being a column identifier. (TODO: handle expressions) 
+        * and the second being an optional boolean indicating if DISTINCT 
+        * needs to be added.
+        * 
+        * @param args The column to apply the function to.
+        * @throws IllegalArgumentException If at least one argument has not 
+        *                              been supplied or the second argument 
+        *                              object is not Boolean.
+        */                              
+        public void setArguments( Object[] args )
+                                            throws IllegalArgumentException
+        {
+
+            if ( args.length < 1 ) 
+            {
+                throw new IllegalArgumentException(
+                      "There must be at least one argument object specified!");
+            }
+            if ( args.length < 2 ) 
+            {
+                this.distinct = false;
+            } 
+            else 
+            {
+                if ( ! ( args[1] instanceof Boolean ) ) 
+                {
+                    throw new IllegalArgumentException(
+                           "Second argument object is not type Boolean!");
+                }
+                this.distinct = ((Boolean) args[1]).booleanValue();
+            }
+            addArgument( args[0].toString() );
+            this.argumentsSet = true;
+        }
+        
+        /**
+         * Should the column have DISTINCT added in front of it?
+         * 
+         * @return True if DISTINCT is needed.
+         */
+        public boolean isDistinct() 
+        {
+            return this.distinct;
+        }
+        
+        /**
+         * Get the function name to use, e.g. AVG, MIN, LEAST.
+         * 
+         * @return The function.
+         */
+        protected String getFunction() 
+        {
+            return this.function;
+        }
+        
+        /**
+         * Set the function to use.
+         *  
+         * @param value The function to use.
+         */
+        public void setFunction( String value ) 
+        {
+            this.function = value;
+        }
+        
+        /**
+         * Generate the SQL for this function.
+         */
+        public String toSQL() 
+                    throws IllegalStateException
+        {
+            if ( ! argumentsSet ) 
+            {
+                throw new IllegalStateException ( 
+                               "Function arguments have not been set!");
+            }
+            StringBuffer sb = new StringBuffer();
+            sb.append(getFunction()).append("(");
+            if ( isDistinct() ) 
+            {
+                sb.append("DISTINCT ");
+            }
+            sb.append( getArgument(0).toString() ).append( ")" );
+            return sb.toString();
+        }
+
+        /* (non-Javadoc)
+         * @see org.apache.torque.util.functions.AbstractFunction#getArgument(int)
+         */
+        public String getArgument(int index)
+        {
+            return (String) getArgumentObject(index);
+        }
+        
+    }
+
+    /**
+     * SQL99 Standard Average a column function.
+     */
+    public class Avg extends Aggregate.AgregateFunction
+    {
+        /**
+         * Construct an AVG function class.
+         * 
+         * @see Aggregate.AgregateFunction
+         * @see FunctionFactory
+         */
+        protected Avg() 
+        {
+            super();
+            setFunction("AVG");
+        }
+    }
+
+    /**
+     * SQL99 Standard Count records function.
+     */
+    public class Count extends Aggregate.AgregateFunction 
+    {
+        /**
+         * Construct a COUNT function class.
+         * 
+         * @see Aggregate.AgregateFunction
+         * @see FunctionFactory
+         */
+        protected Count() 
+        {
+            super();
+            setFunction("COUNT");
+        }
+    }
+
+    /**
+     * SQL99 Standard Minimum value of column function.
+     */
+    public class Min extends Aggregate.AgregateFunction 
+    {
+        /**
+         * Construct a MIN function class.
+         * 
+         * @see Aggregate.AgregateFunction
+         * @see FunctionFactory
+         */
+        protected Min() 
+        {
+            super();
+            setFunction("MIN");
+        }
+    }
+
+    /**
+     * SQL99 Standard maximum value of column function.
+     */
+    public class Max extends Aggregate.AgregateFunction 
+    {
+        /**
+         * Construct a MAX function class.
+         * 
+         * @see FunctionFactory
+         * @see Aggregate.AgregateFunction
+         */
+        protected Max( ) 
+        {
+            super();
+            setFunction("MAX");
+        }
+    }
+
+    /**
+     * SQL99 Standard sum column values function.
+     */
+    public class Sum extends Aggregate.AgregateFunction 
+    {
+        /**
+         * Construct a SUM function class.
+         * 
+         * @see FunctionFactory
+         * @see Aggregate.AgregateFunction
+         */
+        protected Sum( ) 
+        {
+            super();
+            setFunction("SUM");
+        }
+    }
+}

Added: db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionEnum.java
URL: http://svn.apache.org/viewvc/db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionEnum.java?rev=643209&view=auto
==============================================================================
--- db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionEnum.java (added)
+++ db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionEnum.java Mon Mar 31 16:33:41 2008
@@ -0,0 +1,107 @@
+package org.apache.torque.util.functions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * A typesafe enum of SQL Standard function names.  Used by the 
+ * FunctionFactory and (eventually) the DB Adaptors to create SQLFunction
+ * objects. 
+ *
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
+ * @version $Id
+ */
+public class FunctionEnum implements java.io.Serializable
+{
+    /**
+     * Serial version
+     */
+    private static final long serialVersionUID = 5963149836513364800L;
+
+    /** The AVG( [Distinct] EXPR ) function id */
+    public static final FunctionEnum AVG =
+                                new FunctionEnum("AVG");
+    /** The SUM( [Distinct] EXPR ) function id */
+    public static final FunctionEnum SUM =
+                                new FunctionEnum("SUM");
+    /** The MAX( [Distinct] EXPR ) function id */
+    public static final FunctionEnum MAX =
+                                new FunctionEnum("MAX");
+    /** The MIN( [Distinct] EXPR ) function id */
+    public static final FunctionEnum MIN =
+                                new FunctionEnum("MIN");
+    /** The COUNT( [Distinct] EXPR ) function id */
+    public static final FunctionEnum COUNT =
+                                new FunctionEnum("COUNT");
+
+    private final String s;
+
+    /**
+     * This is a static only class.
+     * @param s
+     */
+  
+    private FunctionEnum(String s)
+    {
+        this.s = s;
+    }
+
+    public final String toString()
+    {
+        return s;
+    }
+
+    /**
+     * returns whether o is the same FunctionEnum as this object.
+     * Two FunctionEnums are considered equal if they contain the same String.
+     * @param o the object to compare the FunctionEnum with.
+     */
+    public boolean equals(Object o)
+    {
+        if (o == null)
+        {
+            return false;
+        }
+
+        if (!(o instanceof FunctionEnum))
+        {
+            return false;
+        }
+
+        FunctionEnum otherEnum = (FunctionEnum) o;
+
+
+        // both null: true
+        // other null, this not null: false
+        // else compare
+        return (otherEnum.s == null)
+                ? (s == null)
+                : otherEnum.s.equals(s);
+    }
+
+    /**
+     * returns a hashcode for this object which is consistent with equals()
+     */
+    public int hashCode()
+    {
+        return (s == null)
+                ? 0
+                : s.hashCode();
+    }
+}

Added: db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionFactory.java
URL: http://svn.apache.org/viewvc/db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionFactory.java?rev=643209&view=auto
==============================================================================
--- db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionFactory.java (added)
+++ db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/FunctionFactory.java Mon Mar 31 16:33:41 2008
@@ -0,0 +1,295 @@
+package org.apache.torque.util.functions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.lang.reflect.Constructor;
+
+import org.apache.torque.Torque;
+import org.apache.torque.adapter.DB;
+
+/**
+ * <p>This class is a "Factory class" for creating SQLFunction implementation
+ * classes. It works with the DB adaptor classes to create functions that
+ * are appropriate for the specified (or default) db server type.</p>
+ * 
+ * <p>The generic method for doing this is the 
+ * functionInstance(String, FunctionEnum, Object[]) method.  However, there are
+ * a variety of convenience methods that can be used to quickly created 
+ * specific functions, e.g. avg( Object ) and the like.</p>
+ * 
+ * @see SQLFunction
+ * @see SummaryHelper
+ * 
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
+ * @version $Id
+ */
+public class FunctionFactory
+{
+    /**
+     * This class only has static methods and shouldn't be created.
+     */
+    private FunctionFactory () 
+    {        
+    }
+    
+    /**
+     * Create an AVG SQL function implementation.
+     * 
+     * @param dbName The name of the Torque db 
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @param distinct If true, the function expr will have be prefaced 
+     *                 with "DISTINCT", e.g. function(DISTINCT column).
+     * @return The function object to use.
+     * @throws Exception
+     */
+    public static final SQLFunction avg ( String dbName, Object expr1, 
+                                          boolean distinct )
+                                                         throws Exception
+    {
+        return functionInstance( dbName, FunctionEnum.AVG, 
+                                 new Object[]{ expr1, new Boolean(distinct) });
+    }
+    /**
+     * Convenience method for creating a non-distinct function that uses
+     * the default DB.  
+     *   
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @return The function object to use.
+     * @throws Exception 
+     */
+    public static final SQLFunction avg ( Object expr1 ) 
+                                                throws Exception
+    {
+        return avg ( null, expr1, false );
+    }
+    
+    /**
+     * Create a COUNT SQL function implementation.
+     * 
+     * @param dbName The name of the Torque db 
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @param distinct If true, the function expr will have be prefaced 
+     *                 with "DISTINCT", e.g. function(DISTINCT column).
+     * @return The function object to use.
+     * @throws Exception
+     */
+    public static final SQLFunction count ( String dbName, Object expr1, 
+                                          boolean distinct )
+                                                         throws Exception
+    {
+        return functionInstance( dbName, FunctionEnum.COUNT,
+                                 new Object[]{ expr1, new Boolean(distinct) });
+    }
+    /**
+     * Convenience method for creating a non-distinct function that uses
+     * the default DB.  
+     *   
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @return The function object to use.
+     * @throws Exception 
+     */
+    public static final SQLFunction count ( Object expr1 ) 
+                                                throws Exception
+    {
+        return count ( null, expr1, false );
+    }
+    
+    /**
+     * Create a MAX SQL function implementation.
+     * 
+     * @param dbName The name of the Torque db 
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @param distinct If true, the function expr will have be prefaced 
+     *                 with "DISTINCT", e.g. function(DISTINCT column).
+     * @return The function object to use.
+     * @throws Exception
+     */
+    public static final SQLFunction max ( String dbName, Object expr1, 
+                                          boolean distinct )
+                                                         throws Exception
+    {
+        return functionInstance( dbName, FunctionEnum.MAX,
+                                 new Object[]{ expr1, new Boolean(distinct) });
+    }
+    /**
+     * Convenience method for creating a non-distinct function that uses
+     * the default DB.  
+     *   
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @return The function object to use.
+     * @throws Exception 
+     */
+    public static final SQLFunction max ( Object expr1 ) 
+                                                throws Exception
+    {
+        return max ( null, expr1, false );
+    }
+    
+    /**
+     * Create a MIN SQL function implementation.
+     * 
+     * @param dbName The name of the Torque db 
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @param distinct If true, the function expr will have be prefaced 
+     *                 with "DISTINCT", e.g. function(DISTINCT column).
+     * @return The function object to use.
+     * @throws Exception
+     */
+    public static final SQLFunction min ( String dbName, Object expr1, 
+                                          boolean distinct )
+                                                         throws Exception
+    {
+        return functionInstance( dbName, FunctionEnum.MIN,
+                                 new Object[]{ expr1, new Boolean(distinct) });
+    }
+    /**
+     * Convenience method for creating a non-distinct function that uses
+     * the default DB.  
+     *   
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @return The function object to use.
+     * @throws Exception 
+     */
+    public static final SQLFunction min ( Object expr1 ) 
+                                                throws Exception
+    {
+        return min ( null, expr1, false );
+    }
+    
+    /**
+     * Create a SUM SQL function implementation.
+     * 
+     * @param dbName The name of the Torque db 
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @param distinct If true, the function expr will have be prefaced 
+     *                 with "DISTINCT", e.g. function(DISTINCT column).
+     * @return The function object to use.
+     * @throws Exception
+     */
+    public static final SQLFunction sum ( String dbName, Object expr1, 
+                                          boolean distinct )
+                                                         throws Exception
+    {
+        return functionInstance( dbName, FunctionEnum.SUM,
+                                  new Object[]{ expr1, new Boolean(distinct) });
+    }
+    /**
+     * Convenience method for creating a non-distinct function that uses
+     * the default DB.  
+     *   
+     * @param expr1 The expression to apply the function to.  Generally a 
+     *              column name in table.column format.  It is assumed
+     *              that the "toString()" method of this object will be
+     *              acceptable for an argument.
+     * @return The function object to use.
+     * @throws Exception 
+     */
+    public static final SQLFunction sum ( Object expr1 ) 
+                                                throws Exception
+    {
+        return sum ( null, expr1, false );
+    }
+    
+    /**
+     * "Generic" function class creation method.
+     * 
+     * @param dbName  The name of the Torque DB this function applies to or 
+     *                the default Torque DB if null.
+     * @param function  The function to create an object for.
+     * @param arguments The arguments required by the function object.
+     * @return A SQLFunction implementation that for the specified DB server. 
+     * @throws Exception
+     */
+    public static final SQLFunction functionInstance ( String dbName, 
+                                                       FunctionEnum function,
+                                                       Object[] arguments )
+                                                           throws Exception 
+   {
+        DB dbAdaptor = null;
+        if ( dbName != null ) {
+           dbAdaptor = Torque.getDB(dbName);
+        } 
+        else 
+        {
+            dbAdaptor = Torque.getDB(Torque.getDefaultDB());
+        }
+        Class fClass = dbAdaptor.getFunctionClass( function );
+        if ( fClass == null ) 
+        {
+            throw new IllegalArgumentException(
+              "Could not find function class for '"+ function.toString() +"'");
+        }
+
+        Object fInstance = null;
+        
+        // Check if class is an inner class 
+        Class outerClass = fClass.getDeclaringClass();
+        if ( outerClass != null ) 
+        {
+            Object oInstance = outerClass.newInstance();
+            Constructor iConstructor = 
+                fClass.getDeclaredConstructor( new Class[] { outerClass } );
+            fInstance = iConstructor.newInstance( new Object[] { oInstance });
+        }
+        else
+        {
+            fInstance = fClass.newInstance();
+        }
+        SQLFunction func = (SQLFunction) fInstance;
+        func.setArguments( arguments );
+        func.setDBName( dbName );
+        
+        return func;
+   }
+
+    public static final SQLFunction functionInstance ( FunctionEnum function,
+                                                       Object[] arguments )
+                                                           throws Exception 
+   {
+        return functionInstance ( null, function, arguments );
+   }
+}

Added: db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/SQLFunction.java
URL: http://svn.apache.org/viewvc/db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/SQLFunction.java?rev=643209&view=auto
==============================================================================
--- db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/SQLFunction.java (added)
+++ db/torque/runtime/trunk/src/java/org/apache/torque/util/functions/SQLFunction.java Mon Mar 31 16:33:41 2008
@@ -0,0 +1,91 @@
+package org.apache.torque.util.functions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Define the basic methods that classes that support SQL Functions
+ * need to implement for Classes that use them.  This is intended to 
+ * allow code to be written before functions are fully integrated 
+ * with the DBAdaptors.  As well as allowing for functions to
+ * expand as needed. 
+ * 
+ * @see FunctionFactory
+ * 
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
+ * @version $Id
+ */
+public interface SQLFunction
+{
+    /**
+     * This should return the SQL string that can be used
+     * when constructing the query.  E.g. "AVG( table.column )" or
+     * CONCAT(table.column, " foobar");
+     *  
+     * @return The SQL String.
+     */
+    public abstract String toSQL();
+    
+    /**
+     * Return a string representation of the function parameters
+     * at index i.  Should be null if parameter does not exist.
+     * 
+     * @param i The 0 based parameter to get.
+     * @return A String representation of the parameter.  Null if one does not
+     *         exist.
+     */
+    public abstract String getArgument( int i );
+    
+    /**
+     * Return all the parameters as an object array. This allow for 
+     * processing of the parameters in their original format rather
+     * than just in String format.  E.g. a parameter might be specified
+     * as a Date object, or a Column object.
+     * 
+     * @return Should return a valid Object array and not null.  E.g. 
+     *  implementors should return new Object[0] if there are no parameters.
+     */
+    public abstract Object[] getArguments();
+    
+    /**
+     * Sets the function specific arguments.  Note, this should generally 
+     * only be called by FunctionFactory.
+     * 
+     * @param args The function specific arguments.
+     */
+    public abstract void setArguments( Object[] args );
+    
+    /**
+     * Get the name of the Torque Database associated with this function.
+     * 
+     * @return The DB name.  Should not be null (use default DB in this case).
+     * @exception IllegalStateException If Torque has not been initialized and
+     *   the default DB name can not be determined.
+     */
+    public abstract String getDBName() throws IllegalStateException;
+    
+    /**
+     * Sets the Torque DB name this function is being used with.
+     * 
+     * @param dbName The DB name, if null, the getDBName will return default DB
+     *               name (if it can be determined).
+     */
+    public abstract void setDBName( String dbName );
+
+}

Added: db/torque/test/trunk/test-project/src/java/org/apache/torque/util/SummaryHelperTest.java
URL: http://svn.apache.org/viewvc/db/torque/test/trunk/test-project/src/java/org/apache/torque/util/SummaryHelperTest.java?rev=643209&view=auto
==============================================================================
--- db/torque/test/trunk/test-project/src/java/org/apache/torque/util/SummaryHelperTest.java (added)
+++ db/torque/test/trunk/test-project/src/java/org/apache/torque/util/SummaryHelperTest.java Mon Mar 31 16:33:41 2008
@@ -0,0 +1,247 @@
+package org.apache.torque.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.StringWriter;
+import java.util.List;
+
+import org.apache.commons.collections.OrderedMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.torque.BaseRuntimeTestCase;
+import org.apache.torque.test.Summarize1;
+import org.apache.torque.test.Summarize1Peer;
+import org.apache.torque.util.functions.FunctionFactory;
+
+import com.workingdogs.village.Value;
+
+
+/**
+ * Test code for SummaryHelper.
+ *
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
+ * @version $Id
+ */
+public class SummaryHelperTest extends BaseRuntimeTestCase
+{
+    static Log logger = LogFactory.getLog( SummaryHelperTest.class );
+
+    private static final String[] TEST_GROUPBY1  = {
+        "A1","B1","C1","D1"
+    };
+    private static final int[] TEST_GROUPBY1_TYPE  = {
+        1, 2, 1, 2
+    };
+    private static final String[] TEST_GROUPBY2  = {
+        "A2","B2","C2","D2"
+    };
+
+    private Criteria criteria;
+
+    /**
+     * Creates a new instance.
+     */
+    public SummaryHelperTest(String name)
+    {
+        super(name);
+    }
+
+    public void setUp() throws Exception
+    {
+        super.setUp();
+
+        // Clean up any previous failures
+
+        criteria = new Criteria();
+        criteria.add( Summarize1Peer.ID, -99, SqlEnum.GREATER_THAN);
+        Summarize1Peer.doDelete(criteria);
+        criteria = null;
+
+        // Create some test data
+        for (int i = 0; i < TEST_GROUPBY1.length; i++)
+        {
+            for ( int j = 0; j < TEST_GROUPBY2.length; j++ ) {
+                Summarize1 rec = new Summarize1();
+                rec.setGroupBy1(TEST_GROUPBY1[i]);
+                rec.setGroupBy2(TEST_GROUPBY2[j]);
+                rec.setType(TEST_GROUPBY1_TYPE[j]);
+                rec.setInt1( i+1 * (j+1) );
+                rec.setFloat1( (i+1 * (j+1)) / 0.5f );
+                rec.save();
+            }
+        }
+    }
+
+    public void tearDown() throws Exception
+    {
+        // Delete the test data
+/*
+        criteria = new Criteria();
+        criteria.add( Summarize1Peer.ID, -99, SqlEnum.GREATER_THAN);
+        Summarize1Peer.doDelete(criteria);
+        criteria = null;
+*/
+    }
+
+    /*
+     * Test a simple single table with group bys
+     */
+    public void testSummarize()
+                        throws Exception
+    {
+        Criteria c = new Criteria();
+
+        c.addAscendingOrderByColumn(Summarize1Peer.GROUP_BY1);
+
+        SummaryHelper summary = new SummaryHelper();
+
+        summary.setExcludeExprColumns(true);
+        summary.addGroupBy ( Summarize1Peer.GROUP_BY1 );
+        summary.addAggregate("Count_recs",
+                                FunctionFactory.count(Summarize1Peer.ID));
+        summary.addAggregate("Avg_int1",
+                                FunctionFactory.avg(Summarize1Peer.INT_1));
+        summary.addAggregate("Min_int1",
+                                FunctionFactory.min(Summarize1Peer.INT_1));
+        summary.addAggregate("Max_int1",
+                                FunctionFactory.max(Summarize1Peer.INT_1));
+        summary.addAggregate("Sum_int1",
+                                FunctionFactory.sum(Summarize1Peer.INT_1));
+
+        summary.addAggregate("Avg_float1",
+                                FunctionFactory.avg(Summarize1Peer.FLOAT1));
+        summary.addAggregate("Min_float1",
+                                FunctionFactory.min(Summarize1Peer.FLOAT1));
+        summary.addAggregate("Max_float1",
+                                FunctionFactory.max(Summarize1Peer.FLOAT1));
+        summary.addAggregate("Sum_float1",
+                                FunctionFactory.sum(Summarize1Peer.FLOAT1));
+
+        List results = summary.summarize( c );
+
+        StringWriter out = new StringWriter();
+        summary.dumpResults(out, results, true);
+        out.close();
+        logger.debug("\n"+out.toString());
+
+        assertTrue("No results returned", results.size() > 0 );
+        assertTrue("Invalid number of records returned. Expected 4 but got " +
+                       results.size(), results.size() == 4 );
+
+        OrderedMap rec = (OrderedMap) results.get(0);
+
+        assertTrue( "Number of columns incorrect! Expected 10 but got " +
+                        rec.size(), rec.size() == 10 );
+        assertTrue( "group_by1 valued not correct",
+                "A1".equals(((Value) rec.get("group_by1")).asString()) );
+        assertTrue("Count_recs not correct value",
+                ((Value) rec.get("Count_recs")).asInt() == 4 );
+        assertTrue("Avg_int1 not correct value",
+                ((Value) rec.get("Avg_int1")).asInt() == 2 );
+        assertTrue("Min_int1 not correct value",
+                ((Value) rec.get("Min_int1")).asInt() == 1 );
+        assertTrue("Max_int1 not correct value",
+                ((Value) rec.get("Max_int1")).asInt() == 4 );
+        assertTrue("Sum_int1 not correct value",
+                ((Value) rec.get("Sum_int1")).asInt() == 10 );
+
+        rec = (OrderedMap) results.get(3);
+        assertTrue( "Number of columns incorrect! Expected 10 but got " +
+                        rec.size(), rec.size() == 10 );
+        assertTrue( "group_by1 valued not correct",
+                "D1".equals(((Value) rec.get("group_by1")).asString()) );
+        assertTrue("Count_recs not correct value",
+                ((Value) rec.get("Count_recs")).asInt() == 4 );
+        assertTrue("Avg_float1 not correct value",
+                ((Value) rec.get("Avg_float1")).asFloat() == 11.0f );
+        assertTrue("Min_float1 not correct value",
+                ((Value) rec.get("Min_float1")).asFloat() == 8.0f );
+        assertTrue("Max_float1 not correct value",
+                ((Value) rec.get("Max_float1")).asFloat() == 14.0f );
+        assertTrue("Sum_float1_recs not correct value",
+                ((Value) rec.get("Sum_float1")).asFloat() == 44.0f );
+
+    }
+    /*
+     * Test a total table aggregate summaries (no group bys)
+     */
+    public void testSummarizeEntireTable() throws Exception {
+        Criteria c = new Criteria();
+
+        SummaryHelper summary = new SummaryHelper();
+
+        summary.setExcludeExprColumns(true);
+        summary.addAggregate("Count_recs",
+                                FunctionFactory.count(Summarize1Peer.ID));
+        summary.addAggregate("Avg_int1",
+                                FunctionFactory.avg(Summarize1Peer.INT_1));
+        summary.addAggregate("Min_int1",
+                                FunctionFactory.min(Summarize1Peer.INT_1));
+        summary.addAggregate("Max_int1",
+                                FunctionFactory.max(Summarize1Peer.INT_1));
+        summary.addAggregate("Sum_int1",
+                                FunctionFactory.sum(Summarize1Peer.INT_1));
+
+        summary.addAggregate("Avg_float1",
+                FunctionFactory.avg(Summarize1Peer.FLOAT1));
+        summary.addAggregate("Min_float1",
+                FunctionFactory.min(Summarize1Peer.FLOAT1));
+        summary.addAggregate("Max_float1",
+                FunctionFactory.max(Summarize1Peer.FLOAT1));
+        summary.addAggregate("Sum_float1",
+                FunctionFactory.sum(Summarize1Peer.FLOAT1));
+
+        List results = summary.summarize(c);
+
+        StringWriter out = new StringWriter();
+        summary.dumpResults(out, results, true);
+        out.close();
+        logger.debug("\n"+out.toString());
+
+        assertTrue("No results returned", results.size() > 0 );
+        assertTrue("Invalid number of records returned.  Expected 1 but got " +
+                       results.size(), results.size() == 1 );
+
+        OrderedMap rec = (OrderedMap) results.get(0);
+
+        assertTrue( "Number of columns incorrect! Did ExcludeExpColumns work? " +
+                       "Expected 9 but got " + rec.size(), rec.size() == 9 );
+        assertTrue("Count_recs not correct value",
+                ((Value) rec.get("Count_recs")).asInt() == 16 );
+        assertTrue("Avg_int1 not correct value",
+                ((Value) rec.get("Avg_int1")).asInt() == 4 );
+        assertTrue("Min_int1 not correct value",
+                ((Value) rec.get("Min_int1")).asInt() == 1 );
+        assertTrue("Max_int1 not correct value",
+                ((Value) rec.get("Max_int1")).asInt() == 7 );
+        assertTrue("Sum_int1 not correct value",
+                ((Value) rec.get("Sum_int1")).asInt() == 64 );
+
+        assertTrue("Avg_float1 not correct value",
+                ((Value) rec.get("Avg_float1")).asFloat() == 8.0f );
+        assertTrue("Min_float1 not correct value",
+                ((Value) rec.get("Min_float1")).asFloat() == 2.0f );
+        assertTrue("Max_float1 not correct value",
+                ((Value) rec.get("Max_float1")).asFloat() == 14.0f );
+        assertTrue("Sum_float1_recs not correct value",
+                ((Value) rec.get("Sum_float1")).asFloat() == 128.0f );
+    }
+
+}

Modified: db/torque/test/trunk/test-project/src/schema/test-schema.xml
URL: http://svn.apache.org/viewvc/db/torque/test/trunk/test-project/src/schema/test-schema.xml?rev=643209&r1=643208&r2=643209&view=diff
==============================================================================
--- db/torque/test/trunk/test-project/src/schema/test-schema.xml (original)
+++ db/torque/test/trunk/test-project/src/schema/test-schema.xml Mon Mar 31 16:33:41 2008
@@ -485,4 +485,15 @@
     <column name="p_double" type="DOUBLE" javaType="primitive" />
   </table>
   
+  <!--  Table to test SummaryHelper class  -->
+  <table name="summerize1" description="Test table for summaryHelper class" >
+    <column name="id" required="true" primaryKey="true" type="INTEGER" 
+            description="id column" autoIncrement="true" />
+    <column name="group_by1" type="VARCHAR" javaType="primitive" size="100" />
+    <column name="group_by2" type="VARCHAR" javaType="primitive" size="100" />
+    <column name="int_1" type="INTEGER" javaType="primitive" />
+    <column name="float1" type="FLOAT" javaType="primitive" />
+    <column name="type" type="INTEGER" javaType="primitive" />
+  </table>
+  
 </database>



---------------------------------------------------------------------
To unsubscribe, e-mail: torque-dev-unsubscribe@db.apache.org
For additional commands, e-mail: torque-dev-help@db.apache.org


Mime
View raw message