You are viewing a plain text version of this content. The canonical link for it is here.
Posted to torque-dev@db.apache.org by tf...@apache.org on 2013/02/20 22:06:37 UTC
svn commit: r1448414 [8/14] - in
/db/torque/torque4/trunk/torque-runtime/src: main/java/org/apache/torque/
main/java/org/apache/torque/adapter/ main/java/org/apache/torque/criteria/
main/java/org/apache/torque/map/ main/java/org/apache/torque/oid/ main...
Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/SummaryHelper.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/SummaryHelper.java?rev=1448414&r1=1448413&r2=1448414&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/SummaryHelper.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/SummaryHelper.java Wed Feb 20 21:06:35 2013
@@ -1,815 +1,815 @@
-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.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Vector;
-
-import org.apache.commons.collections.OrderedMapIterator;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.torque.Column;
-import org.apache.torque.ColumnImpl;
-import org.apache.torque.TorqueException;
-import org.apache.torque.criteria.SqlEnum;
-import org.apache.torque.om.mapper.ObjectListMapper;
-import org.apache.torque.om.mapper.RecordMapper;
-import org.apache.torque.sql.SqlBuilder;
-import org.apache.torque.util.functions.SQLFunction;
-
-/**
- * <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>
- *
- * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
- * @version $Id$
- */
-public class SummaryHelper
-{
- /** The class log. */
- private static Log logger = LogFactory.getLog(SummaryHelper.class);
-
- /** A list of the group by columns. */
- private List<Column> groupByColumns;
- /** A ListOrderMapCI<String, Aggregate.Function> with the aggregate functions
- * to use in generating results. */
- private ListOrderedMapCI aggregates;
- /** Flag for excluding unnamed columns. */
- private boolean excludeExprColumns = false;
-
- /**
- * Return a list of ListOrderedMapCI objects with the results of the summary
- * query. The ListOrderedMapCI objects have a key of the column name or
- * function alias and are in the order generated by the query.
- * The class of the return values are decided by the database driver,
- * which makes this method not database independent.
- *
- * @param crit The base criteria to build on.
- *
- * @return Results as a OrderMap<String, List<Object>> object.
- *
- * @throws TorqueException if a database error occurs.
- *
- * @deprecated please use
- * summarize(org.apache.torque.criteria.Criteria)
- * instead.
- * This method will be removed in a future version of Torque.
- */
- @Deprecated
- public List<ListOrderedMapCI> summarize(Criteria crit)
- throws TorqueException
- {
- return summarize(crit, (List<Class<?>>) null);
- }
-
- /**
- * Return a list of ListOrderedMapCI objects with the results of the summary
- * query. The ListOrderedMapCI objects have a key of the column name or
- * function alias and are in the order generated by the query.
- * The class of the return values are decided by the database driver,
- * which makes this method not database independent.
- *
- * @param crit The base criteria to build on.
- *
- * @return Results as a OrderMap<String, List<Object>> object.
- *
- * @throws TorqueException if a database error occurs.
- */
- public List<ListOrderedMapCI> summarize(
- org.apache.torque.criteria.Criteria crit)
- throws TorqueException
- {
- return summarize(crit, (List<Class<?>>) null);
- }
-
- /**
- * Return a list of ListOrderedMapCI objects with the results of the summary
- * query. The ListOrderedMapCI 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 resultTypes the classes to which the return values of the query
- * should be cast, or null to let the database driver decide.
- * See org.apache.torque.om.mapper.ObjectListMapper�for the supported
- * classes.
- *
- * @return Results as a ListOrderMapCI<String, List<Object>> object.
- *
- * @throws TorqueException if a database error occurs.
- *
- * @deprecated Please use
- * summarize(org.apache.torque.criteria.Criteria, List<Class<?>>)
- * instead.
- * This method will be removed in a future version of Torque.
- */
- @Deprecated
- public List<ListOrderedMapCI> summarize(
- Criteria crit,
- List<Class<?>> resultTypes)
- throws TorqueException
- {
- Connection connection = null;
- try
- {
- connection = Transaction.begin(crit.getDbName());
- List<ListOrderedMapCI> result = summarize(crit, resultTypes, connection);
- Transaction.commit(connection);
- connection = null;
- return result;
- }
- finally
- {
- if (connection != null)
- {
- Transaction.safeRollback(connection);
- }
- }
- }
-
- /**
- * Return a list of ListOrderedMapCI objects with the results of the summary
- * query. The ListOrderedMapCI 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 resultTypes the classes to which the return values of the query
- * should be cast, or null to let the database driver decide.
- * See org.apache.torque.om.mapper.ObjectListMapper�for the supported
- * classes.
- *
- * @return Results as a ListOrderMapCI<String, List<Object>> object.
- *
- * @throws TorqueException if a database error occurs.
- */
- public List<ListOrderedMapCI> summarize(
- org.apache.torque.criteria.Criteria crit,
- List<Class<?>> resultTypes)
- throws TorqueException
- {
- Connection connection = null;
- try
- {
- connection = Transaction.begin(crit.getDbName());
- List<ListOrderedMapCI> result = summarize(crit, resultTypes, connection);
- Transaction.commit(connection);
- connection = null;
- return result;
- }
- finally
- {
- if (connection != null)
- {
- Transaction.safeRollback(connection);
- }
- }
- }
-
- /**
- * 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.
- * The class of the return values are decided by the database driver,
- * which makes this method not database independent.
- *
- * @param crit The base criteria to build on.
- * @param conn The DB Connection to use.
- *
- * @return Results as a OrderMap<String, List<Object>> object.
- *
- * @throws TorqueException if a database error occurs.
- *
- * @deprecated please use
- * summarize(org.apache.torque.criteria.Criteria, Connection)
- * instead.
- * This method will be removed in a future version of Torque.
- */
- @Deprecated
- public List<ListOrderedMapCI> summarize(Criteria crit, Connection conn)
- throws TorqueException
- {
- return summarize(crit, null, conn);
- }
-
- /**
- * 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.
- * The class of the return values are decided by the database driver,
- * which makes this method not database independent.
- *
- * @param crit The base criteria to build on.
- * @param conn The DB Connection to use.
- *
- * @return Results as a OrderMap<String, List<Object>> object.
- *
- * @throws TorqueException if a database error occurs.
- */
- public List<ListOrderedMapCI> summarize(
- org.apache.torque.criteria.Criteria crit,
- Connection conn)
- throws TorqueException
- {
- return summarize(crit, null, conn);
- }
-
- /**
- * Return a list of ListOrderedMapCI objects with the results of the summary
- * query. The ListOrderedMapCI 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 resultTypes the classes to which the return values of the query
- * should be cast, or null to let the database driver decide.
- * See org.apache.torque.om.mapper.ObjectListMapper�for the supported
- * classes.
- * @param conn The DB Connection to use.
- *
- * @return Results as a ListOrderedMapCI<String,Values> object.
- *
- * @throws TorqueException if a database error occurs.
- *
- * @deprecated please use
- * summarize(org.apache.torque.criteria.Criteria, List<Class<?>>, Connection)
- * instead.
- * This method will be removed in a future version of Torque.
- */
- @Deprecated
- public List<ListOrderedMapCI> summarize(
- Criteria crit,
- List<Class<?>> resultTypes,
- Connection conn)
- throws TorqueException
- {
- Criteria c = buildCriteria(crit);
- // TODO use BasePeerImpl.doSelect instead of parsing the result manually
- String query = SqlBuilder.buildQuery(c).toString();
- RecordMapper<List<Object>> mapper = new ObjectListMapper(resultTypes);
-
- Statement statement = null;
- ResultSet resultSet = null;
- List<List<Object>> rows = new ArrayList<List<Object>>();
- try
- {
- statement = conn.createStatement();
- long startTime = System.currentTimeMillis();
- logger.debug("Executing query " + query);
-
- resultSet = statement.executeQuery(query.toString());
- long queryEndTime = System.currentTimeMillis();
- logger.trace("query took " + (queryEndTime - startTime)
- + " milliseconds");
-
- while (resultSet.next())
- {
- List<Object> rowResult = mapper.processRow(resultSet, 0, null);
- rows.add(rowResult);
- }
- long mappingEndTime = System.currentTimeMillis();
- logger.trace("mapping took " + (mappingEndTime - queryEndTime)
- + " milliseconds");
- }
- catch (SQLException e)
- {
- throw new TorqueException(e);
- }
- finally
- {
- if (resultSet != null)
- {
- try
- {
- resultSet.close();
- }
- catch (SQLException e)
- {
- logger.warn("error closing resultSet", e);
- }
- }
- if (statement != null)
- {
- try
- {
- statement.close();
- }
- catch (SQLException e)
- {
- logger.warn("error closing statement", e);
- }
- }
- }
-
- List<ListOrderedMapCI> resultsList = new Vector<ListOrderedMapCI>(rows.size());
- List<String> columnNames = new ArrayList<String>();
- for (Column column : c.getSelectColumns())
- {
- columnNames.add(column.getColumnName());
- }
- columnNames.addAll(c.getAsColumns().keySet());
- for (List<Object> row : rows)
- {
- ListOrderedMapCI recordMap = new ListOrderedMapCI();
- for (int i = 0; i < row.size(); i++)
- {
- Object value = row.get(i);
- String cName = columnNames.get(i);
- if (cName == null || cName.equals(""))
- {
- if (excludeExprColumns())
- {
- continue;
- }
- cName = "Expr" + i;
- }
- recordMap.put(cName, value);
- }
- resultsList.add(recordMap);
- }
- return resultsList;
- }
-
- /**
- * Return a list of ListOrderedMapCI objects with the results of the summary
- * query. The ListOrderedMapCI 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 resultTypes the classes to which the return values of the query
- * should be cast, or null to let the database driver decide.
- * See org.apache.torque.om.mapper.ObjectListMapper�for the supported
- * classes.
- * @param conn The DB Connection to use.
- *
- * @return Results as a ListOrderedMapCI<String,Values> object.
- *
- * @throws TorqueException if a database error occurs.
- */
- public List<ListOrderedMapCI> summarize(
- org.apache.torque.criteria.Criteria crit,
- List<Class<?>> resultTypes,
- Connection conn)
- throws TorqueException
- {
- org.apache.torque.criteria.Criteria c = buildCriteria(crit);
- // TODO use BasePeerImpl.doSelect instead of parsing the result manually
- String query = SqlBuilder.buildQuery(c).toString();
- RecordMapper<List<Object>> mapper = new ObjectListMapper(resultTypes);
-
- Statement statement = null;
- ResultSet resultSet = null;
- List<List<Object>> rows = new ArrayList<List<Object>>();
- try
- {
- statement = conn.createStatement();
- long startTime = System.currentTimeMillis();
- logger.debug("Executing query " + query);
-
- resultSet = statement.executeQuery(query.toString());
- long queryEndTime = System.currentTimeMillis();
- logger.trace("query took " + (queryEndTime - startTime)
- + " milliseconds");
-
- while (resultSet.next())
- {
- List<Object> rowResult = mapper.processRow(resultSet, 0, null);
- rows.add(rowResult);
- }
- long mappingEndTime = System.currentTimeMillis();
- logger.trace("mapping took " + (mappingEndTime - queryEndTime)
- + " milliseconds");
- }
- catch (SQLException e)
- {
- throw new TorqueException(e);
- }
- finally
- {
- if (resultSet != null)
- {
- try
- {
- resultSet.close();
- }
- catch (SQLException e)
- {
- logger.warn("error closing resultSet", e);
- }
- }
- if (statement != null)
- {
- try
- {
- statement.close();
- }
- catch (SQLException e)
- {
- logger.warn("error closing statement", e);
- }
- }
- }
-
- List<ListOrderedMapCI> resultsList = new Vector<ListOrderedMapCI>(rows.size());
- List<String> columnNames = new ArrayList<String>();
- for (Column column : c.getSelectColumns())
- {
- columnNames.add(column.getColumnName());
- }
- columnNames.addAll(c.getAsColumns().keySet());
- for (List<Object> row : rows)
- {
- ListOrderedMapCI recordMap = new ListOrderedMapCI();
- for (int i = 0; i < row.size(); i++)
- {
- Object value = row.get(i);
- String cName = columnNames.get(i);
- 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
- *
- * @deprecated please use
- * buildCriteria(org.apache.torque.criteria.Criteria)
- * instead.
- * This method will be removed in a future version of Torque.
- */
- @Deprecated
- public Criteria buildCriteria(Criteria c) throws TorqueException
- {
- c.getSelectColumns().clear();
- c.getGroupByColumns().clear();
-
- UniqueList<String> criteriaSelectModifiers;
- criteriaSelectModifiers = c.getSelectModifiers();
-
- if (criteriaSelectModifiers != null
- && criteriaSelectModifiers.size() > 0
- && criteriaSelectModifiers.contains(SqlEnum.DISTINCT.toString()))
- {
- criteriaSelectModifiers.remove(SqlEnum.DISTINCT.toString());
- }
- c.setIgnoreCase(false);
-
- List<Column> cols = getGroupByColumns();
- boolean haveFromTable = !cols.isEmpty(); // Group By cols define src table.
- for (Column col : cols)
- {
- 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.isEmpty())
- {
- haveFromTable = true;
- logger.debug("From table defined by a where clause");
- }
-
- ListOrderedMapCI cMap = getAggregates();
- OrderedMapIterator iMap = cMap.orderedMapIterator();
- while (iMap.hasNext())
- {
- String key = (String) iMap.next();
- SQLFunction f = (SQLFunction) iMap.getValue();
- Column col = f.getColumn();
- c.addAsColumn(key, new ColumnImpl(
- null,
- col.getTableName(),
- col.getColumnName(),
- f.getSqlExpression()));
- if (!haveFromTable) // Last chance. Get it from the func.
- {
- {
- // Kludgy Where table.col = table.col clause to force
- // from table identification.
- c.add(col,
- (col.getColumnName()
- + "=" + col.getColumnName()),
- SqlEnum.CUSTOM);
- haveFromTable = true;
-
- String table = col.getTableName();
- 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;
- }
-
- /**
- * 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 org.apache.torque.criteria.Criteria buildCriteria(
- org.apache.torque.criteria.Criteria c) throws TorqueException
- {
- c.getSelectColumns().clear();
- c.getGroupByColumns().clear();
-
- UniqueList<String> criteriaSelectModifiers;
- criteriaSelectModifiers = c.getSelectModifiers();
-
- if (criteriaSelectModifiers != null
- && criteriaSelectModifiers.size() > 0
- && criteriaSelectModifiers.contains(SqlEnum.DISTINCT.toString()))
- {
- criteriaSelectModifiers.remove(SqlEnum.DISTINCT.toString());
- }
- c.setIgnoreCase(false);
-
- List<Column> cols = getGroupByColumns();
- boolean haveFromTable = !cols.isEmpty(); // Group By cols define src table.
- for (Column col : cols)
- {
- 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.getTopLevelCriterion() != null)
- {
- haveFromTable = true;
- logger.debug("From table defined by a where clause");
- }
-
- ListOrderedMapCI cMap = getAggregates();
- OrderedMapIterator iMap = cMap.orderedMapIterator();
- while (iMap.hasNext())
- {
- String key = (String) iMap.next();
- SQLFunction f = (SQLFunction) iMap.getValue();
- Column col = f.getColumn();
- c.addAsColumn(key, new ColumnImpl(
- null,
- col.getTableName(),
- col.getColumnName(),
- f.getSqlExpression()));
- if (!haveFromTable) // Last chance. Get it from the func.
- {
- {
- // Kludgy Where table.col = table.col clause to force
- // from table identification.
- c.and(col,
- (col.getColumnName()
- + "=" + col.getColumnName()),
- SqlEnum.CUSTOM);
- haveFromTable = true;
-
- String table = col.getTableName();
- 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(Column 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<Column> getGroupByColumns()
- {
- if (groupByColumns == null)
- {
- groupByColumns = new Vector<Column>();
- }
- 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 ListOrderedMapCI getAggregates()
- {
- if (aggregates == null)
- {
- aggregates = new ListOrderedMapCI();
- }
- 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())
- {
- ListOrderedMapCI rec = (ListOrderedMapCI) i.next();
- OrderedMapIterator rI = rec.orderedMapIterator();
- StringBuilder heading = new StringBuilder();
- StringBuilder recString = new StringBuilder();
- while (rI.hasNext())
- {
- String colId = (String) rI.next();
- if (first)
- {
- heading.append("\"").append(colId).append("\"");
- if (rI.hasNext())
- {
- heading.append(", ");
- }
- }
- Object v = rI.getValue();
- recString.append(v.toString());
- if (rI.hasNext())
- {
- recString.append(", ");
- }
- }
- if (first)
- {
- first = false;
- out.write(heading.toString());
- out.write("\n");
- }
- out.write(recString.toString());
- 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;
- }
-}
+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.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.commons.collections.OrderedMapIterator;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.torque.Column;
+import org.apache.torque.ColumnImpl;
+import org.apache.torque.TorqueException;
+import org.apache.torque.criteria.SqlEnum;
+import org.apache.torque.om.mapper.ObjectListMapper;
+import org.apache.torque.om.mapper.RecordMapper;
+import org.apache.torque.sql.SqlBuilder;
+import org.apache.torque.util.functions.SQLFunction;
+
+/**
+ * <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>
+ *
+ * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
+ * @version $Id$
+ */
+public class SummaryHelper
+{
+ /** The class log. */
+ private static Log logger = LogFactory.getLog(SummaryHelper.class);
+
+ /** A list of the group by columns. */
+ private List<Column> groupByColumns;
+ /** A ListOrderMapCI<String, Aggregate.Function> with the aggregate functions
+ * to use in generating results. */
+ private ListOrderedMapCI aggregates;
+ /** Flag for excluding unnamed columns. */
+ private boolean excludeExprColumns = false;
+
+ /**
+ * Return a list of ListOrderedMapCI objects with the results of the summary
+ * query. The ListOrderedMapCI objects have a key of the column name or
+ * function alias and are in the order generated by the query.
+ * The class of the return values are decided by the database driver,
+ * which makes this method not database independent.
+ *
+ * @param crit The base criteria to build on.
+ *
+ * @return Results as a OrderMap<String, List<Object>> object.
+ *
+ * @throws TorqueException if a database error occurs.
+ *
+ * @deprecated please use
+ * summarize(org.apache.torque.criteria.Criteria)
+ * instead.
+ * This method will be removed in a future version of Torque.
+ */
+ @Deprecated
+ public List<ListOrderedMapCI> summarize(Criteria crit)
+ throws TorqueException
+ {
+ return summarize(crit, (List<Class<?>>) null);
+ }
+
+ /**
+ * Return a list of ListOrderedMapCI objects with the results of the summary
+ * query. The ListOrderedMapCI objects have a key of the column name or
+ * function alias and are in the order generated by the query.
+ * The class of the return values are decided by the database driver,
+ * which makes this method not database independent.
+ *
+ * @param crit The base criteria to build on.
+ *
+ * @return Results as a OrderMap<String, List<Object>> object.
+ *
+ * @throws TorqueException if a database error occurs.
+ */
+ public List<ListOrderedMapCI> summarize(
+ org.apache.torque.criteria.Criteria crit)
+ throws TorqueException
+ {
+ return summarize(crit, (List<Class<?>>) null);
+ }
+
+ /**
+ * Return a list of ListOrderedMapCI objects with the results of the summary
+ * query. The ListOrderedMapCI 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 resultTypes the classes to which the return values of the query
+ * should be cast, or null to let the database driver decide.
+ * See org.apache.torque.om.mapper.ObjectListMapper�for the supported
+ * classes.
+ *
+ * @return Results as a ListOrderMapCI<String, List<Object>> object.
+ *
+ * @throws TorqueException if a database error occurs.
+ *
+ * @deprecated Please use
+ * summarize(org.apache.torque.criteria.Criteria, List<Class<?>>)
+ * instead.
+ * This method will be removed in a future version of Torque.
+ */
+ @Deprecated
+ public List<ListOrderedMapCI> summarize(
+ Criteria crit,
+ List<Class<?>> resultTypes)
+ throws TorqueException
+ {
+ Connection connection = null;
+ try
+ {
+ connection = Transaction.begin(crit.getDbName());
+ List<ListOrderedMapCI> result = summarize(crit, resultTypes, connection);
+ Transaction.commit(connection);
+ connection = null;
+ return result;
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ Transaction.safeRollback(connection);
+ }
+ }
+ }
+
+ /**
+ * Return a list of ListOrderedMapCI objects with the results of the summary
+ * query. The ListOrderedMapCI 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 resultTypes the classes to which the return values of the query
+ * should be cast, or null to let the database driver decide.
+ * See org.apache.torque.om.mapper.ObjectListMapper�for the supported
+ * classes.
+ *
+ * @return Results as a ListOrderMapCI<String, List<Object>> object.
+ *
+ * @throws TorqueException if a database error occurs.
+ */
+ public List<ListOrderedMapCI> summarize(
+ org.apache.torque.criteria.Criteria crit,
+ List<Class<?>> resultTypes)
+ throws TorqueException
+ {
+ Connection connection = null;
+ try
+ {
+ connection = Transaction.begin(crit.getDbName());
+ List<ListOrderedMapCI> result = summarize(crit, resultTypes, connection);
+ Transaction.commit(connection);
+ connection = null;
+ return result;
+ }
+ finally
+ {
+ if (connection != null)
+ {
+ Transaction.safeRollback(connection);
+ }
+ }
+ }
+
+ /**
+ * 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.
+ * The class of the return values are decided by the database driver,
+ * which makes this method not database independent.
+ *
+ * @param crit The base criteria to build on.
+ * @param conn The DB Connection to use.
+ *
+ * @return Results as a OrderMap<String, List<Object>> object.
+ *
+ * @throws TorqueException if a database error occurs.
+ *
+ * @deprecated please use
+ * summarize(org.apache.torque.criteria.Criteria, Connection)
+ * instead.
+ * This method will be removed in a future version of Torque.
+ */
+ @Deprecated
+ public List<ListOrderedMapCI> summarize(Criteria crit, Connection conn)
+ throws TorqueException
+ {
+ return summarize(crit, null, conn);
+ }
+
+ /**
+ * 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.
+ * The class of the return values are decided by the database driver,
+ * which makes this method not database independent.
+ *
+ * @param crit The base criteria to build on.
+ * @param conn The DB Connection to use.
+ *
+ * @return Results as a OrderMap<String, List<Object>> object.
+ *
+ * @throws TorqueException if a database error occurs.
+ */
+ public List<ListOrderedMapCI> summarize(
+ org.apache.torque.criteria.Criteria crit,
+ Connection conn)
+ throws TorqueException
+ {
+ return summarize(crit, null, conn);
+ }
+
+ /**
+ * Return a list of ListOrderedMapCI objects with the results of the summary
+ * query. The ListOrderedMapCI 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 resultTypes the classes to which the return values of the query
+ * should be cast, or null to let the database driver decide.
+ * See org.apache.torque.om.mapper.ObjectListMapper�for the supported
+ * classes.
+ * @param conn The DB Connection to use.
+ *
+ * @return Results as a ListOrderedMapCI<String,Values> object.
+ *
+ * @throws TorqueException if a database error occurs.
+ *
+ * @deprecated please use
+ * summarize(org.apache.torque.criteria.Criteria, List<Class<?>>, Connection)
+ * instead.
+ * This method will be removed in a future version of Torque.
+ */
+ @Deprecated
+ public List<ListOrderedMapCI> summarize(
+ Criteria crit,
+ List<Class<?>> resultTypes,
+ Connection conn)
+ throws TorqueException
+ {
+ Criteria c = buildCriteria(crit);
+ // TODO use BasePeerImpl.doSelect instead of parsing the result manually
+ String query = SqlBuilder.buildQuery(c).toString();
+ RecordMapper<List<Object>> mapper = new ObjectListMapper(resultTypes);
+
+ Statement statement = null;
+ ResultSet resultSet = null;
+ List<List<Object>> rows = new ArrayList<List<Object>>();
+ try
+ {
+ statement = conn.createStatement();
+ long startTime = System.currentTimeMillis();
+ logger.debug("Executing query " + query);
+
+ resultSet = statement.executeQuery(query.toString());
+ long queryEndTime = System.currentTimeMillis();
+ logger.trace("query took " + (queryEndTime - startTime)
+ + " milliseconds");
+
+ while (resultSet.next())
+ {
+ List<Object> rowResult = mapper.processRow(resultSet, 0, null);
+ rows.add(rowResult);
+ }
+ long mappingEndTime = System.currentTimeMillis();
+ logger.trace("mapping took " + (mappingEndTime - queryEndTime)
+ + " milliseconds");
+ }
+ catch (SQLException e)
+ {
+ throw new TorqueException(e);
+ }
+ finally
+ {
+ if (resultSet != null)
+ {
+ try
+ {
+ resultSet.close();
+ }
+ catch (SQLException e)
+ {
+ logger.warn("error closing resultSet", e);
+ }
+ }
+ if (statement != null)
+ {
+ try
+ {
+ statement.close();
+ }
+ catch (SQLException e)
+ {
+ logger.warn("error closing statement", e);
+ }
+ }
+ }
+
+ List<ListOrderedMapCI> resultsList = new Vector<ListOrderedMapCI>(rows.size());
+ List<String> columnNames = new ArrayList<String>();
+ for (Column column : c.getSelectColumns())
+ {
+ columnNames.add(column.getColumnName());
+ }
+ columnNames.addAll(c.getAsColumns().keySet());
+ for (List<Object> row : rows)
+ {
+ ListOrderedMapCI recordMap = new ListOrderedMapCI();
+ for (int i = 0; i < row.size(); i++)
+ {
+ Object value = row.get(i);
+ String cName = columnNames.get(i);
+ if (cName == null || cName.equals(""))
+ {
+ if (excludeExprColumns())
+ {
+ continue;
+ }
+ cName = "Expr" + i;
+ }
+ recordMap.put(cName, value);
+ }
+ resultsList.add(recordMap);
+ }
+ return resultsList;
+ }
+
+ /**
+ * Return a list of ListOrderedMapCI objects with the results of the summary
+ * query. The ListOrderedMapCI 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 resultTypes the classes to which the return values of the query
+ * should be cast, or null to let the database driver decide.
+ * See org.apache.torque.om.mapper.ObjectListMapper�for the supported
+ * classes.
+ * @param conn The DB Connection to use.
+ *
+ * @return Results as a ListOrderedMapCI<String,Values> object.
+ *
+ * @throws TorqueException if a database error occurs.
+ */
+ public List<ListOrderedMapCI> summarize(
+ org.apache.torque.criteria.Criteria crit,
+ List<Class<?>> resultTypes,
+ Connection conn)
+ throws TorqueException
+ {
+ org.apache.torque.criteria.Criteria c = buildCriteria(crit);
+ // TODO use BasePeerImpl.doSelect instead of parsing the result manually
+ String query = SqlBuilder.buildQuery(c).toString();
+ RecordMapper<List<Object>> mapper = new ObjectListMapper(resultTypes);
+
+ Statement statement = null;
+ ResultSet resultSet = null;
+ List<List<Object>> rows = new ArrayList<List<Object>>();
+ try
+ {
+ statement = conn.createStatement();
+ long startTime = System.currentTimeMillis();
+ logger.debug("Executing query " + query);
+
+ resultSet = statement.executeQuery(query.toString());
+ long queryEndTime = System.currentTimeMillis();
+ logger.trace("query took " + (queryEndTime - startTime)
+ + " milliseconds");
+
+ while (resultSet.next())
+ {
+ List<Object> rowResult = mapper.processRow(resultSet, 0, null);
+ rows.add(rowResult);
+ }
+ long mappingEndTime = System.currentTimeMillis();
+ logger.trace("mapping took " + (mappingEndTime - queryEndTime)
+ + " milliseconds");
+ }
+ catch (SQLException e)
+ {
+ throw new TorqueException(e);
+ }
+ finally
+ {
+ if (resultSet != null)
+ {
+ try
+ {
+ resultSet.close();
+ }
+ catch (SQLException e)
+ {
+ logger.warn("error closing resultSet", e);
+ }
+ }
+ if (statement != null)
+ {
+ try
+ {
+ statement.close();
+ }
+ catch (SQLException e)
+ {
+ logger.warn("error closing statement", e);
+ }
+ }
+ }
+
+ List<ListOrderedMapCI> resultsList = new Vector<ListOrderedMapCI>(rows.size());
+ List<String> columnNames = new ArrayList<String>();
+ for (Column column : c.getSelectColumns())
+ {
+ columnNames.add(column.getColumnName());
+ }
+ columnNames.addAll(c.getAsColumns().keySet());
+ for (List<Object> row : rows)
+ {
+ ListOrderedMapCI recordMap = new ListOrderedMapCI();
+ for (int i = 0; i < row.size(); i++)
+ {
+ Object value = row.get(i);
+ String cName = columnNames.get(i);
+ 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
+ *
+ * @deprecated please use
+ * buildCriteria(org.apache.torque.criteria.Criteria)
+ * instead.
+ * This method will be removed in a future version of Torque.
+ */
+ @Deprecated
+ public Criteria buildCriteria(Criteria c) throws TorqueException
+ {
+ c.getSelectColumns().clear();
+ c.getGroupByColumns().clear();
+
+ UniqueList<String> criteriaSelectModifiers;
+ criteriaSelectModifiers = c.getSelectModifiers();
+
+ if (criteriaSelectModifiers != null
+ && criteriaSelectModifiers.size() > 0
+ && criteriaSelectModifiers.contains(SqlEnum.DISTINCT.toString()))
+ {
+ criteriaSelectModifiers.remove(SqlEnum.DISTINCT.toString());
+ }
+ c.setIgnoreCase(false);
+
+ List<Column> cols = getGroupByColumns();
+ boolean haveFromTable = !cols.isEmpty(); // Group By cols define src table.
+ for (Column col : cols)
+ {
+ 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.isEmpty())
+ {
+ haveFromTable = true;
+ logger.debug("From table defined by a where clause");
+ }
+
+ ListOrderedMapCI cMap = getAggregates();
+ OrderedMapIterator iMap = cMap.orderedMapIterator();
+ while (iMap.hasNext())
+ {
+ String key = (String) iMap.next();
+ SQLFunction f = (SQLFunction) iMap.getValue();
+ Column col = f.getColumn();
+ c.addAsColumn(key, new ColumnImpl(
+ null,
+ col.getTableName(),
+ col.getColumnName(),
+ f.getSqlExpression()));
+ if (!haveFromTable) // Last chance. Get it from the func.
+ {
+ {
+ // Kludgy Where table.col = table.col clause to force
+ // from table identification.
+ c.add(col,
+ (col.getColumnName()
+ + "=" + col.getColumnName()),
+ SqlEnum.CUSTOM);
+ haveFromTable = true;
+
+ String table = col.getTableName();
+ 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;
+ }
+
+ /**
+ * 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 org.apache.torque.criteria.Criteria buildCriteria(
+ org.apache.torque.criteria.Criteria c) throws TorqueException
+ {
+ c.getSelectColumns().clear();
+ c.getGroupByColumns().clear();
+
+ UniqueList<String> criteriaSelectModifiers;
+ criteriaSelectModifiers = c.getSelectModifiers();
+
+ if (criteriaSelectModifiers != null
+ && criteriaSelectModifiers.size() > 0
+ && criteriaSelectModifiers.contains(SqlEnum.DISTINCT.toString()))
+ {
+ criteriaSelectModifiers.remove(SqlEnum.DISTINCT.toString());
+ }
+ c.setIgnoreCase(false);
+
+ List<Column> cols = getGroupByColumns();
+ boolean haveFromTable = !cols.isEmpty(); // Group By cols define src table.
+ for (Column col : cols)
+ {
+ 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.getTopLevelCriterion() != null)
+ {
+ haveFromTable = true;
+ logger.debug("From table defined by a where clause");
+ }
+
+ ListOrderedMapCI cMap = getAggregates();
+ OrderedMapIterator iMap = cMap.orderedMapIterator();
+ while (iMap.hasNext())
+ {
+ String key = (String) iMap.next();
+ SQLFunction f = (SQLFunction) iMap.getValue();
+ Column col = f.getColumn();
+ c.addAsColumn(key, new ColumnImpl(
+ null,
+ col.getTableName(),
+ col.getColumnName(),
+ f.getSqlExpression()));
+ if (!haveFromTable) // Last chance. Get it from the func.
+ {
+ {
+ // Kludgy Where table.col = table.col clause to force
+ // from table identification.
+ c.and(col,
+ (col.getColumnName()
+ + "=" + col.getColumnName()),
+ SqlEnum.CUSTOM);
+ haveFromTable = true;
+
+ String table = col.getTableName();
+ 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(Column 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<Column> getGroupByColumns()
+ {
+ if (groupByColumns == null)
+ {
+ groupByColumns = new Vector<Column>();
+ }
+ 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 ListOrderedMapCI getAggregates()
+ {
+ if (aggregates == null)
+ {
+ aggregates = new ListOrderedMapCI();
+ }
+ 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())
+ {
+ ListOrderedMapCI rec = (ListOrderedMapCI) i.next();
+ OrderedMapIterator rI = rec.orderedMapIterator();
+ StringBuilder heading = new StringBuilder();
+ StringBuilder recString = new StringBuilder();
+ while (rI.hasNext())
+ {
+ String colId = (String) rI.next();
+ if (first)
+ {
+ heading.append("\"").append(colId).append("\"");
+ if (rI.hasNext())
+ {
+ heading.append(", ");
+ }
+ }
+ Object v = rI.getValue();
+ recString.append(v.toString());
+ if (rI.hasNext())
+ {
+ recString.append(", ");
+ }
+ }
+ if (first)
+ {
+ first = false;
+ out.write(heading.toString());
+ out.write("\n");
+ }
+ out.write(recString.toString());
+ 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;
+ }
+}
Propchange: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/SummaryHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManager.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManager.java?rev=1448414&r1=1448413&r2=1448414&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManager.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManager.java Wed Feb 20 21:06:35 2013
@@ -1,94 +1,94 @@
-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.sql.Connection;
-
-import org.apache.torque.TorqueException;
-
-/**
- * Torque's interface to the transaction management system.
- *
- * @version $Id$
- */
-public interface TransactionManager
-{
- /**
- * Begin a transaction by retrieving a connection from the default database
- * connection pool.
- * WARNING: If the database does not support transaction or the pool has set
- * autocommit to true on the connection, the database will commit after
- * every statement, regardless of when a commit or rollback is issued.
- *
- * @return The Connection for the transaction.
- * @throws TorqueException Any exceptions caught during processing will be
- * rethrown wrapped into a TorqueException.
- */
- Connection begin() throws TorqueException;
-
- /**
- * Begin a transaction by retrieving a connection from the named database
- * connection pool.
- * WARNING: If the database does not support transaction or the pool has set
- * autocommit to true on the connection, the database will commit after
- * every statement, regardless of when a commit or rollback is issued.
- *
- * @param dbName Name of database.
- *
- * @return The Connection for the transaction.
- *
- * @throws TorqueException If the connection cannot be retrieved.
- */
- Connection begin(String dbName) throws TorqueException;
-
-
- /**
- * Commit a transaction and close the connection.
- * If the connection is in autocommit mode or the database does not support
- * transactions, only a connection close is performed
- *
- * @param con The Connection for the transaction.
- * @throws TorqueException Any exceptions caught during processing will be
- * rethrown wrapped into a TorqueException.
- */
- void commit(Connection con) throws TorqueException;
-
- /**
- * Roll back a transaction and release the connection.
- * In databases that do not support transactions or if autocommit is true,
- * no rollback will be performed, but the connection will be closed anyway.
- *
- * @param con The Connection for the transaction.
- *
- * @throws TorqueException Any exceptions caught during processing will be
- * rethrown wrapped into a TorqueException.
- */
- void rollback(Connection con) throws TorqueException;
-
- /**
- * Roll back a transaction without throwing errors if they occur.
- * A null Connection argument is logged at the debug level and other
- * errors are logged at warn level.
- *
- * @param con The Connection for the transaction.
- * @see TransactionManagerImpl#rollback(Connection)
- */
- void safeRollback(Connection con);
-}
+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.sql.Connection;
+
+import org.apache.torque.TorqueException;
+
+/**
+ * Torque's interface to the transaction management system.
+ *
+ * @version $Id$
+ */
+public interface TransactionManager
+{
+ /**
+ * Begin a transaction by retrieving a connection from the default database
+ * connection pool.
+ * WARNING: If the database does not support transaction or the pool has set
+ * autocommit to true on the connection, the database will commit after
+ * every statement, regardless of when a commit or rollback is issued.
+ *
+ * @return The Connection for the transaction.
+ * @throws TorqueException Any exceptions caught during processing will be
+ * rethrown wrapped into a TorqueException.
+ */
+ Connection begin() throws TorqueException;
+
+ /**
+ * Begin a transaction by retrieving a connection from the named database
+ * connection pool.
+ * WARNING: If the database does not support transaction or the pool has set
+ * autocommit to true on the connection, the database will commit after
+ * every statement, regardless of when a commit or rollback is issued.
+ *
+ * @param dbName Name of database.
+ *
+ * @return The Connection for the transaction.
+ *
+ * @throws TorqueException If the connection cannot be retrieved.
+ */
+ Connection begin(String dbName) throws TorqueException;
+
+
+ /**
+ * Commit a transaction and close the connection.
+ * If the connection is in autocommit mode or the database does not support
+ * transactions, only a connection close is performed
+ *
+ * @param con The Connection for the transaction.
+ * @throws TorqueException Any exceptions caught during processing will be
+ * rethrown wrapped into a TorqueException.
+ */
+ void commit(Connection con) throws TorqueException;
+
+ /**
+ * Roll back a transaction and release the connection.
+ * In databases that do not support transactions or if autocommit is true,
+ * no rollback will be performed, but the connection will be closed anyway.
+ *
+ * @param con The Connection for the transaction.
+ *
+ * @throws TorqueException Any exceptions caught during processing will be
+ * rethrown wrapped into a TorqueException.
+ */
+ void rollback(Connection con) throws TorqueException;
+
+ /**
+ * Roll back a transaction without throwing errors if they occur.
+ * A null Connection argument is logged at the debug level and other
+ * errors are logged at warn level.
+ *
+ * @param con The Connection for the transaction.
+ * @see TransactionManagerImpl#rollback(Connection)
+ */
+ void safeRollback(Connection con);
+}
Propchange: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManager.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManagerImpl.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManagerImpl.java?rev=1448414&r1=1448413&r2=1448414&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManagerImpl.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManagerImpl.java Wed Feb 20 21:06:35 2013
@@ -1,186 +1,186 @@
-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.sql.Connection;
-import java.sql.SQLException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.torque.Torque;
-import org.apache.torque.TorqueException;
-
-/**
- * Standard connection and transaction management for Torque.
- * Uses JDBC connection operations and Torque's own database pools
- * for managing connections and transactions.
- *
- * @author <a href="mailto:stephenh@chase3000.com">Stephen Haberman</a>
- * @version $Id$
- */
-public class TransactionManagerImpl implements TransactionManager
-{
-
- /** The log. */
- private static Log log = LogFactory.getLog(TransactionManagerImpl.class);
-
- /**
- * Begin a transaction by retrieving a connection from the default database
- * connection pool.
- * WARNING: If the database does not support transaction or the pool has set
- * autocommit to true on the connection, the database will commit after
- * every statement, regardless of when a commit or rollback is issued.
- *
- * @return The Connection for the transaction.
- * @throws TorqueException Any exceptions caught during processing will be
- * rethrown wrapped into a TorqueException.
- */
- public Connection begin() throws TorqueException
- {
- return begin(Torque.getDefaultDB());
- }
-
- /**
- * Begin a transaction by retrieving a connection from the named database
- * connection pool.
- * WARNING: If the database does not support transaction or the pool has set
- * autocommit to true on the connection, the database will commit after
- * every statement, regardless of when a commit or rollback is issued.
- *
- * @param dbName Name of database.
- *
- * @return The Connection for the transaction.
- *
- * @throws TorqueException If the connection cannot be retrieved.
- */
- public Connection begin(String dbName) throws TorqueException
- {
- Connection con = Torque.getConnection(dbName);
- return con;
- }
-
-
- /**
- * Commit a transaction and close the connection.
- * If the connection is in autocommit mode or the database does not support
- * transactions, only a connection close is performed
- *
- * @param con The Connection for the transaction.
- * @throws TorqueException Any exceptions caught during processing will be
- * rethrown wrapped into a TorqueException.
- */
- public void commit(Connection con) throws TorqueException
- {
- if (con == null)
- {
- throw new NullPointerException("Connection object was null. "
- + "This could be due to a misconfiguration of the "
- + "DataSourceFactory. Check the logs and Torque.properties "
- + "to better determine the cause.");
- }
-
- try
- {
- if (con.getMetaData().supportsTransactions()
- && !con.getAutoCommit())
- {
- con.commit();
- }
- }
- catch (SQLException e)
- {
- throw new TorqueException(e);
- }
- finally
- {
- Torque.closeConnection(con);
- }
- }
-
- /**
- * Roll back a transaction and release the connection.
- * In databases that do not support transactions or if autocommit is true,
- * no rollback will be performed, but the connection will be closed anyway.
- *
- * @param con The Connection for the transaction.
- *
- * @throws TorqueException Any exceptions caught during processing will be
- * rethrown wrapped into a TorqueException.
- */
- public void rollback(Connection con) throws TorqueException
- {
- if (con == null)
- {
- throw new TorqueException("Connection object was null. "
- + "This could be due to a misconfiguration of the "
- + "DataSourceFactory. Check the logs and Torque.properties "
- + "to better determine the cause.");
- }
- else
- {
- try
- {
- if (con.getMetaData().supportsTransactions()
- && !con.getAutoCommit())
- {
- con.rollback();
- }
- }
- catch (SQLException e)
- {
- log.error("An attempt was made to rollback a transaction "
- + "but the database did not allow the operation to be "
- + "rolled back.", e);
- throw new TorqueException(e);
- }
- finally
- {
- Torque.closeConnection(con);
- }
- }
- }
-
- /**
- * Roll back a transaction without throwing errors if they occur.
- * A null Connection argument is logged at the debug level and other
- * errors are logged at warn level.
- *
- * @param con The Connection for the transaction.
- * @see TransactionManagerImpl#rollback(Connection)
- */
- public void safeRollback(Connection con)
- {
- if (con == null)
- {
- log.debug("called safeRollback with null argument");
- }
- else
- {
- try
- {
- rollback(con);
- }
- catch (TorqueException e)
- {
- log.warn("An error occured during rollback.", e);
- }
- }
- }
-}
+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.sql.Connection;
+import java.sql.SQLException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.torque.Torque;
+import org.apache.torque.TorqueException;
+
+/**
+ * Standard connection and transaction management for Torque.
+ * Uses JDBC connection operations and Torque's own database pools
+ * for managing connections and transactions.
+ *
+ * @author <a href="mailto:stephenh@chase3000.com">Stephen Haberman</a>
+ * @version $Id$
+ */
+public class TransactionManagerImpl implements TransactionManager
+{
+
+ /** The log. */
+ private static Log log = LogFactory.getLog(TransactionManagerImpl.class);
+
+ /**
+ * Begin a transaction by retrieving a connection from the default database
+ * connection pool.
+ * WARNING: If the database does not support transaction or the pool has set
+ * autocommit to true on the connection, the database will commit after
+ * every statement, regardless of when a commit or rollback is issued.
+ *
+ * @return The Connection for the transaction.
+ * @throws TorqueException Any exceptions caught during processing will be
+ * rethrown wrapped into a TorqueException.
+ */
+ public Connection begin() throws TorqueException
+ {
+ return begin(Torque.getDefaultDB());
+ }
+
+ /**
+ * Begin a transaction by retrieving a connection from the named database
+ * connection pool.
+ * WARNING: If the database does not support transaction or the pool has set
+ * autocommit to true on the connection, the database will commit after
+ * every statement, regardless of when a commit or rollback is issued.
+ *
+ * @param dbName Name of database.
+ *
+ * @return The Connection for the transaction.
+ *
+ * @throws TorqueException If the connection cannot be retrieved.
+ */
+ public Connection begin(String dbName) throws TorqueException
+ {
+ Connection con = Torque.getConnection(dbName);
+ return con;
+ }
+
+
+ /**
+ * Commit a transaction and close the connection.
+ * If the connection is in autocommit mode or the database does not support
+ * transactions, only a connection close is performed
+ *
+ * @param con The Connection for the transaction.
+ * @throws TorqueException Any exceptions caught during processing will be
+ * rethrown wrapped into a TorqueException.
+ */
+ public void commit(Connection con) throws TorqueException
+ {
+ if (con == null)
+ {
+ throw new NullPointerException("Connection object was null. "
+ + "This could be due to a misconfiguration of the "
+ + "DataSourceFactory. Check the logs and Torque.properties "
+ + "to better determine the cause.");
+ }
+
+ try
+ {
+ if (con.getMetaData().supportsTransactions()
+ && !con.getAutoCommit())
+ {
+ con.commit();
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new TorqueException(e);
+ }
+ finally
+ {
+ Torque.closeConnection(con);
+ }
+ }
+
+ /**
+ * Roll back a transaction and release the connection.
+ * In databases that do not support transactions or if autocommit is true,
+ * no rollback will be performed, but the connection will be closed anyway.
+ *
+ * @param con The Connection for the transaction.
+ *
+ * @throws TorqueException Any exceptions caught during processing will be
+ * rethrown wrapped into a TorqueException.
+ */
+ public void rollback(Connection con) throws TorqueException
+ {
+ if (con == null)
+ {
+ throw new TorqueException("Connection object was null. "
+ + "This could be due to a misconfiguration of the "
+ + "DataSourceFactory. Check the logs and Torque.properties "
+ + "to better determine the cause.");
+ }
+ else
+ {
+ try
+ {
+ if (con.getMetaData().supportsTransactions()
+ && !con.getAutoCommit())
+ {
+ con.rollback();
+ }
+ }
+ catch (SQLException e)
+ {
+ log.error("An attempt was made to rollback a transaction "
+ + "but the database did not allow the operation to be "
+ + "rolled back.", e);
+ throw new TorqueException(e);
+ }
+ finally
+ {
+ Torque.closeConnection(con);
+ }
+ }
+ }
+
+ /**
+ * Roll back a transaction without throwing errors if they occur.
+ * A null Connection argument is logged at the debug level and other
+ * errors are logged at warn level.
+ *
+ * @param con The Connection for the transaction.
+ * @see TransactionManagerImpl#rollback(Connection)
+ */
+ public void safeRollback(Connection con)
+ {
+ if (con == null)
+ {
+ log.debug("called safeRollback with null argument");
+ }
+ else
+ {
+ try
+ {
+ rollback(con);
+ }
+ catch (TorqueException e)
+ {
+ log.warn("An error occured during rollback.", e);
+ }
+ }
+ }
+}
Propchange: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/TransactionManagerImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/UniqueColumnList.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/UniqueColumnList.java?rev=1448414&r1=1448413&r2=1448414&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/UniqueColumnList.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/UniqueColumnList.java Wed Feb 20 21:06:35 2013
@@ -1,101 +1,101 @@
-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.util.ArrayList;
-
-import org.apache.torque.Column;
-
-/**
- * List with unique entries. UniqueList does not allow null nor will
- * Columns with the same SQL expression be added twice.
- *
- * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
- * @version $Id$
- */
-public class UniqueColumnList extends ArrayList<Column>
-{
- /**
- * Serial version
- */
- private static final long serialVersionUID = 4467847559423445120L;
-
- /**
- * Constructs an empty UniqueList.
- */
- public UniqueColumnList()
- {
- // empty
- }
-
- /**
- * Copy-constructor. Creates a shallow copy of an UniqueList.
- * @param list the uniqueList to copy
- */
- public UniqueColumnList(UniqueColumnList list)
- {
- this.addAll(list);
- }
-
- /**
- * Adds a Column to the list, if no column with the same SQL Expression
- * is not already contained.
- *
- * @param column the Column to add, not null.
- *
- * @return true if the Object is added.
- *
- * @throws NullPointerException if column is null.
- */
- public boolean add(Column column)
- {
- if (column == null)
- {
- throw new NullPointerException("column must not be null");
- }
- if (!containsSqlExpression(column))
- {
- return super.add(column);
- }
- return false;
- }
-
- /**
- * Checks if this list already contains a column with the same
- * SQL expression.
- *
- * @param column the column to check, not null.
- *
- * @return true if a column with the same Sql Expression is contained,
- * false otherwise.
- */
- public boolean containsSqlExpression(Column column)
- {
- for (Column candidate : this)
- {
- if (candidate.getSqlExpression().equals(
- column.getSqlExpression()))
- {
- return true;
- }
- }
- return false;
- }
-}
+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.util.ArrayList;
+
+import org.apache.torque.Column;
+
+/**
+ * List with unique entries. UniqueList does not allow null nor will
+ * Columns with the same SQL expression be added twice.
+ *
+ * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
+ * @version $Id$
+ */
+public class UniqueColumnList extends ArrayList<Column>
+{
+ /**
+ * Serial version
+ */
+ private static final long serialVersionUID = 4467847559423445120L;
+
+ /**
+ * Constructs an empty UniqueList.
+ */
+ public UniqueColumnList()
+ {
+ // empty
+ }
+
+ /**
+ * Copy-constructor. Creates a shallow copy of an UniqueList.
+ * @param list the uniqueList to copy
+ */
+ public UniqueColumnList(UniqueColumnList list)
+ {
+ this.addAll(list);
+ }
+
+ /**
+ * Adds a Column to the list, if no column with the same SQL Expression
+ * is not already contained.
+ *
+ * @param column the Column to add, not null.
+ *
+ * @return true if the Object is added.
+ *
+ * @throws NullPointerException if column is null.
+ */
+ public boolean add(Column column)
+ {
+ if (column == null)
+ {
+ throw new NullPointerException("column must not be null");
+ }
+ if (!containsSqlExpression(column))
+ {
+ return super.add(column);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if this list already contains a column with the same
+ * SQL expression.
+ *
+ * @param column the column to check, not null.
+ *
+ * @return true if a column with the same Sql Expression is contained,
+ * false otherwise.
+ */
+ public boolean containsSqlExpression(Column column)
+ {
+ for (Column candidate : this)
+ {
+ if (candidate.getSqlExpression().equals(
+ column.getSqlExpression()))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: torque-dev-unsubscribe@db.apache.org
For additional commands, e-mail: torque-dev-help@db.apache.org