(sorry for wrong posting on turbine-dev)

I'm sending this mainly for illustration of what I'm proposing we do with Torque to 
improve performance and maintainability.  I've tested this in my environment and will 
soon be trusting it in my production environment.  The changes are based on the 
Turbine 2.1 code base which I'll be forced to continue to use for a while.  I'd be 
happy to work the code into the 3.0 code base if the patch will be accepted, but I 
can't afford to spend the time if it will be rejected.

Basically what I've done is stolen the part of the Village API that Torque really 
needs and used only that.  The new SqlValue class I am adding is really just the 
village.Value class with expanded privileges, and new constructors.  This new class 
can be used for PreparedStatements and processing ResultSets throughout the BasePeer 
class, without using the entire Village API.  

Perhaps an even better solution would be for the Criteria to use SqlValue objects 
internally so that when you add a clause to the Criteria it would determine the SQL 
type of the parameter right then.  The Critera code would have the opportunity to 
raise an exception if the supplied value cannot be converted to the necessary SQL 
type.  Then errors can be caught before the actual select or update operation is 
performed and traced back to real culprit more easily.

At the moment, the only part of the Village API that doUpdate uses is the Schema 
class, simply because it caches table meta-data for us.  The code to replace this 
could possibly be added to the Map classes.

- Chris


__________________________________________________________________
The NEW Netscape 7.0 browser is now available. Upgrade now! 
http://channels.netscape.com/ns/browsers/download.jsp 

Get your own FREE, personal Netscape Mail account today at http://webmail.netscape.com/
Index: java/org/apache/turbine/om/peer/BasePeer.java
===================================================================
RCS file: 
/usr/local/cvsroot/turbine/src/java/org/apache/turbine/om/peer/BasePeer.java,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 BasePeer.java
--- java/org/apache/turbine/om/peer/BasePeer.java   2001/06/14 22:28:16 1.1.1.2
+++ java/org/apache/turbine/om/peer/BasePeer.java   2003/01/13 23:17:01
@@ -56,6 +56,7 @@

 import com.workingdogs.village.Column;
 import com.workingdogs.village.DataSet;
+import com.workingdogs.village.DataSetException;
 import com.workingdogs.village.KeyDef;
 import com.workingdogs.village.QueryDataSet;
 import com.workingdogs.village.Record;
@@ -71,6 +72,7 @@
 import java.sql.DatabaseMetaData;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
+import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Date;
 import java.util.Enumeration;
@@ -89,6 +91,8 @@
 import org.apache.turbine.services.resources.TurbineResources;
 import org.apache.turbine.util.Log;
 import org.apache.turbine.util.StringStackBuffer;
+import org.apache.turbine.util.TurbineException;
+import org.apache.turbine.util.db.*;
 import org.apache.turbine.util.db.Criteria;
 import org.apache.turbine.util.db.IdGenerator;
 import org.apache.turbine.util.db.Query;
@@ -1586,30 +1590,22 @@
         }
     }

-
     /**
-     * Use this method for performing an update of the kind:
-     *
-     * <p>
-     *
-     * WHERE some_column = some value AND could_have_another_column =
-     * another value AND so on.
-     *
-     * <p>
-     *
-     * Method used to update rows in the DB.  Rows are selected based
-     * on selectCriteria and updated using values in updateValues.
-     *
-     * @param selectCriteria A Criteria object containing values used
-     * in where clause.
+     * Perform a SQL UPDATE using the Village API.  This method should be
+     * deprecated since it is very inefficient.  It is left here to allow
+     * comparison testing.
+     * 
+     * @param selectCriteria A Criteria object containing values used in where
+     * clause.
      * @param updateValues A Criteria object containing values used in
      * set clause.
      * @param dbCon A DBConnection.
      * @exception Exception, a generic exception.
      */
-    public static void doUpdate(Criteria selectCriteria,
-                                Criteria updateValues,
-                                DBConnection dbCon)
+    private static void doUpdateUsingVillage(
+      Criteria selectCriteria,
+      Criteria updateValues,
+      DBConnection dbCon)
         throws Exception
     {
         DB db = TurbineDB.getDB( selectCriteria.getDbName() );
@@ -1685,6 +1681,205 @@
                 if (tds != null) tds.close();
             }
         }
+    }
+
+    /**
+     * Perform a SQL UPDATE using JDBC directly.  This method is more efficient
+     * than {@see #doUpdateUsingVillage(Criteria, Criteria, DBConnection)}
+     * because it does not require the records to be SELECTed before they can
+     * be UPDATEd.
+     *
+     * @param selectCriteria A Criteria object containing values used
+     * in where clause.
+     * @param updateValues A Criteria object containing values used in
+     * set clause.
+     * @param dbCon A DBConnection.
+     * @throws Exception
+     * @throws TurbineException
+     * @throws SQLException
+     */
+    private static void doUpdateUsingJdbc(
+        Criteria selectCriteria,
+        Criteria updateValues,
+        DBConnection dbCon)
+        throws Exception, TurbineException, SQLException
+    {
+        DB db = TurbineDB.getDB(selectCriteria.getDbName());
+        DatabaseMap dbMap = TurbineDB.getDatabaseMap(selectCriteria.getDbName());
+        Connection connection = dbCon.getConnection();
+
+        // Set up a list of required tables.  StringStackBuffer.add()
+        // only adds element if it is unique.
+        StringStackBuffer tables = new StringStackBuffer();
+        Enumeration e = selectCriteria.keys();
+        while (e.hasMoreElements())
+        {
+            tables.add(selectCriteria.getTableName((String) e.nextElement()));
+        }
+
+        // Process each table that is referenced in the Criteria and perform the
+        // update on each 1 individually, since SQL UPDATE statements can't
+        // operate on multiple tables.
+        for (int i = 0; i < tables.size(); i++)
+        {
+            // List of clauses in the WHERE portion of the statement
+            StringStackBuffer whereClauseList = new StringStackBuffer();
+            // List of clauses in the UPDATE portion of the statement
+            StringStackBuffer updateClauseList = new StringStackBuffer();
+            // List of SqlValue's to substitute into the PreparedStatement
+            Vector valueList = new Vector();
+
+            String tableName = tables.get(i);
+
+            // Get the Schema object for the table so we can access the meta-data
+            Schema schema = new Schema();
+            schema = schema.schema(connection, tableName);
+
+            int numColumns = schema.numberOfColumns();
+
+            TableMap tableMap = dbMap.getTable(tableName);
+            for (int j = 0; j < numColumns; j++)
+            {
+                Column column = schema.column(j + 1);
+                String columnName = column.name();
+
+                String key =
+                    new StringBuffer(tableName)
+                        .append('.')
+                        .append(columnName)
+                        .toString();
+
+                if (selectCriteria.containsKey(key))
+                {
+                    if (selectCriteria.getComparison(key).equals(Criteria.CUSTOM))
+                    {
+                        whereClauseList.add(selectCriteria.getString(key));
+                    } else
+                    {
+                        whereClauseList.add(
+                            SqlExpression.build(
+                                columnName,
+                                selectCriteria.getValue(key),
+                                selectCriteria.getComparison(key),
+                                selectCriteria.isIgnoreCase(),
+                                db));
+                    }
+                }
+
+                ColumnMap columnDef = tableMap.getColumn(columnName);
+                // If the columnDef can't be found, assume it's not a primary-key.
+                // This allows the Torque definition to differ from the actual table
+                // structure.
+                boolean isPrimaryKey =
+                    (columnDef != null && columnDef.isPrimaryKey());
+                if (!isPrimaryKey && updateValues.containsKey(key))
+                {
+                    updateClauseList.add(columnName + " = ?");
+
+                    Object obj = updateValues.getValue(key);
+                    if (obj instanceof SimpleKey)
+                    {
+                        obj = ((SimpleKey) obj).getValue();
+                    }
+
+                    // Create a SqlValue object with the SQL type for this column.
+                    valueList.add(
+                        new SqlValue(schema.getColumn(columnName).typeEnum(), obj));
+                }
+            }
+
+            // TODO: here we should check if all of the where clauses and update
+            // values in the Criteria were actually used.  If the actual table is
+            // different than the Torque definition it is possible that the user
+            // could construct a faulty Criteria.
+
+            String query =
+                "UPDATE "
+                    + tableName
+                    + " SET "
+                    + updateClauseList.toString(", ")
+                    + " WHERE "
+                    + whereClauseList.toString(" AND ");
+
+            Logger logger =
+                TurbineLogging.getLogger(TurbineConstants.SQL_LOG_FACILITY);
+            logger.debug("BasePeer.doUpdate: statement = " + query);
+
+            PreparedStatement stmt = connection.prepareStatement(query);
+            try
+            {
+
+                // Fill-in all the values in the PreparedStatement.
+                for (int j = 0; j < valueList.size(); j++)
+                {
+                    SqlValue value = (SqlValue) valueList.get(j);
+                    value.setPreparedStatementValue(stmt, j + 1);
+                    logger.debug(
+                        "BasePeer.doUpdate: setValue("
+                            + (j + 1)
+                            + ") = "
+                            + value.getValue());
+                }
+
+                int count = stmt.executeUpdate();
+
+                if (selectCriteria.isSingleRecord())
+                {
+                    if (count > 1)
+                    {
+                        // The current implementation of this method does not use
+                        // the DataSet for anything, so it's safe to pass in NULL.
+                        // However, this method probably shouldn't even be used.
+                        handleMultipleRecords(null);
+                    } else if (count < 1)
+                    {
+                        logger.warn(
+                            "BasePeer.doUpdate: expected 1 record to be "
+                                + "updated but none were.");
+                    }
+                }
+
+            } finally
+            {
+                stmt.close();
+                stmt = null;
+            }
+        }
+    }
+
+    /** Set to true to use the new JDBC method for updates. */
+    public static boolean doUpdatesUsingJdbc = true;
+
+    /**
+     * Use this method for performing an update of the kind:
+     *
+     * <p>
+     *
+     * WHERE some_column = some value AND could_have_another_column =
+     * another value AND so on.
+     *
+     * <p>
+     *
+     * Method used to update rows in the DB.  Rows are selected based
+     * on selectCriteria and updated using values in updateValues.
+     *
+     * @param selectCriteria A Criteria object containing values used
+     * in where clause.
+     * @param updateValues A Criteria object containing values used in
+     * set clause.
+     * @param dbCon A DBConnection.
+     * @exception Exception, a generic exception.
+     */
+    public static void doUpdate(
+        Criteria selectCriteria,
+        Criteria updateValues,
+        DBConnection dbCon)
+        throws Exception
+    {
+        if (doUpdatesUsingJdbc)
+            doUpdateUsingJdbc(selectCriteria, updateValues, dbCon);
+        else
+            doUpdateUsingVillage(selectCriteria, updateValues, dbCon);
     }

     /**
Index: src/java/org/apache/turbine/util/db/SqlValue.java
===================================================================
RCS file: SqlValue.java
diff -N SqlValue.java
--- /dev/null   Mon Jan 13 17:03:52 2003
+++ SqlValue.java   Mon Jan 13 18:17:03 2003
@@ -0,0 +1,1221 @@
+package org.apache.turbine.util.db;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ *    "Apache Turbine" must not be used to endorse or promote products
+ *    derived from this software without prior written permission. For
+ *    written permission, please contact [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache Turbine", nor may "Apache" appear in their name, without
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+
+import java.math.BigDecimal;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Calendar;
+
+
+/**
+ * A <code>SqlValue</code> represents a single cell in a database table. In
+ * other words, it is the cross between a row and column and contains the
+ * information held there.
+ * <BR>
+ * The primary purpose of this class is to convert values between SQL types and
+ * Java types.  This class allows several different data-types to be supplied
+ * for a particular column in a SQL UPDATE, and the appropriate SQL type will be
+ * used.  When performing SELECTs, this class can likewise be used to obtain
+ * any desired Java type regardless of the SQL column type.  If a conversion
+ * cannot be made to/from the specified type, a {@link SqlValueException}
+ * is thrown.
+ *
+ * @author <A HREF="mailto:[EMAIL PROTECTED]";>Chris Felaco</A>
+ * @version $Id$
+ */
+public class SqlValue
+{
+    /** the object that is stored in this object */
+    private Object valueObject;
+    /** what sql type of object is this? */
+    private int type;
+
+    /**
+     * Creates a new Value object based on the columnNumber and type
+     *
+     * @param type java.sql.Type
+     * @param value
+     */
+    public SqlValue(int type, Object value)
+    {
+        this.type = type;
+        this.valueObject = value;
+    }
+
+    /**
+     * Creates a new Value object based on the ResultSet, columnNumber and type
+     *
+     * @param   rs
+     * @param   columnNumber
+     * @param   type
+     * @exception   SQLException
+     */
+    public SqlValue(ResultSet rs, int columnNumber, int type) throws SQLException
+    {
+        this.type = type;
+        init(rs, columnNumber);
+    }
+
+    /**
+     * Creates a new Value object based on the ResultSet and columnNumber.
+     * The SQL type is determined by the ResultSetMetaData.
+     *
+     * @param   rs
+     * @param   columnNumber
+     * @exception   SQLException
+     */
+    public SqlValue(ResultSet rs, int columnNumber) throws SQLException
+    {
+        this.type = rs.getMetaData().getColumnType(columnNumber);
+        init(rs, columnNumber);
+    }
+
+    /**
+     * Initialize the value using the specified columnNumber in the ResultSet.
+     * @param rs
+     * @param columnNumber
+     * @throws SQLException
+     */
+    private void init(ResultSet rs, int columnNumber) throws SQLException
+    {
+        this.valueObject = null;
+
+        if (rs == null)
+            return;
+
+        switch (type())
+        {
+            case Types.BIT :
+                String tmp = rs.getString(columnNumber);
+                if (tmp == null)
+                    valueObject = new Boolean(false);
+                else if (isTrue(tmp))
+                    valueObject = new Boolean(true);
+                else
+                    valueObject = new Boolean(false);
+                break;
+
+            case Types.TINYINT :
+                valueObject = new Byte(rs.getByte(columnNumber));
+                break;
+
+            case Types.BIGINT :
+                valueObject = new Long(rs.getLong(columnNumber));
+                break;
+
+            case Types.SMALLINT :
+                valueObject = new Short(rs.getShort(columnNumber));
+                break;
+
+            case Types.INTEGER :
+                valueObject = new Integer(rs.getInt(columnNumber));
+                break;
+
+            case Types.REAL :
+                valueObject = new Float(rs.getFloat(columnNumber));
+                break;
+
+            case Types.FLOAT :
+            case Types.DOUBLE :
+                valueObject = new Double(rs.getDouble(columnNumber));
+                break;
+
+            case Types.NUMERIC :
+            case Types.DECIMAL :
+                String number = rs.getString(columnNumber);
+                if (number == null)
+                {
+                    valueObject = null;
+                } else
+                {
+                    valueObject = new BigDecimal(number);
+                }
+                break;
+
+            case Types.LONGVARBINARY :
+            case Types.VARBINARY :
+            case Types.BINARY :
+                valueObject = rs.getBytes(columnNumber);
+                break;
+
+            case Types.LONGVARCHAR :
+            case Types.CHAR :
+            case Types.VARCHAR :
+            case Types.OTHER :
+                valueObject = rs.getString(columnNumber);
+                break;
+
+            case Types.DATE :
+                valueObject = rs.getDate(columnNumber);
+                break;
+
+            case Types.TIME :
+                valueObject = rs.getTime(columnNumber);
+                break;
+
+            case Types.TIMESTAMP :
+                valueObject = rs.getTimestamp(columnNumber);
+                break;
+
+            case Types.NULL :
+                valueObject = null;
+                break;
+
+            default :
+                valueObject = rs.getString(columnNumber);
+                break;
+        }
+
+        if (rs.wasNull())
+            valueObject = null;
+    }
+
+    /**
+      * Sets the value of this object
+      *
+      * @param   value
+      */
+    public void setValue(Object value)
+    {
+        this.valueObject = value;
+    }
+
+    /**
+      * Gets the object from this Value
+      *
+      * @return     the object from this Value
+      */
+    public Object getValue()
+    {
+        return this.valueObject;
+    }
+
+    /**
+      * This is used to set a substitution value in a PreparedStatement using
+      * the correct SQL datatype.
+      *
+      * @param   stmt
+      * @param   stmtNumber
+      * @exception   SqlValueException
+      * @exception   SQLException
+      */
+    public void setPreparedStatementValue(
+        PreparedStatement stmt,
+        int stmtNumber)
+        throws SqlValueException, SQLException
+    {
+        if (isNull())
+        {
+            stmt.setNull(stmtNumber, type());
+            return;
+        }
+
+        switch (type())
+        {
+            case Types.BIT :
+                stmt.setBoolean(stmtNumber, this.asBoolean());
+                break;
+
+            case Types.TINYINT :
+                stmt.setByte(stmtNumber, this.asByte());
+                break;
+
+            case Types.BIGINT :
+                stmt.setLong(stmtNumber, this.asLong());
+                break;
+
+            case Types.SMALLINT :
+                stmt.setShort(stmtNumber, this.asShort());
+                break;
+
+            case Types.INTEGER :
+                stmt.setInt(stmtNumber, this.asInt());
+                break;
+
+            case Types.REAL :
+                stmt.setFloat(stmtNumber, this.asFloat());
+                break;
+
+            case Types.FLOAT :
+            case Types.DOUBLE :
+                stmt.setDouble(stmtNumber, this.asDouble());
+                break;
+
+            case Types.NUMERIC :
+            case Types.DECIMAL :
+                stmt.setBigDecimal(stmtNumber, this.asBigDecimal());
+                break;
+
+            case Types.LONGVARBINARY :
+            case Types.VARBINARY :
+            case Types.BINARY :
+                stmt.setBytes(stmtNumber, this.asBytes());
+                break;
+
+            case Types.LONGVARCHAR :
+            case Types.CHAR :
+            case Types.VARCHAR :
+            case Types.OTHER :
+                stmt.setString(stmtNumber, this.asString());
+                break;
+
+            case Types.DATE :
+                stmt.setDate(stmtNumber, this.asDate());
+                break;
+
+            case Types.TIME :
+                stmt.setTime(stmtNumber, this.asTime());
+                break;
+
+            case Types.TIMESTAMP :
+                stmt.setTimestamp(stmtNumber, this.asTimestamp());
+                break;
+
+            case Types.NULL :
+                stmt.setNull(stmtNumber, 0);
+                break;
+
+            default :
+                stmt.setString(stmtNumber, this.asString());
+                break;
+        }
+    }
+
+    /**
+      * Returns the string representation of this object
+      *
+      * @return     a string
+      */
+    public String toString()
+    {
+        return this.asString();
+    }
+
+    /**
+      * Returns the string representation of this object
+      *
+      * @return     a string
+      */
+    public String asString()
+    {
+        if (isNull())
+            return null;
+        else if (isString())
+            return (String) valueObject;
+        else if (isBytes())
+            return new String((byte[]) valueObject);
+        else
+            return valueObject.toString();
+    }
+
+    /**
+      * Get the value as a BigDecimal
+      *
+      * @return     a BigDecimal
+      * @exception   SqlValueException
+      */
+    public BigDecimal asBigDecimal() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isBigDecimal())
+                return (BigDecimal) valueObject;
+            else if (
+                isString()
+                    || isDouble()
+                    || isFloat()
+                    || isInt()
+                    || isLong()
+                    || isShort()
+                    || isByte())
+                return new BigDecimal(asString());
+            else
+                return null;
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Illegal conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a BigDecimal
+      *
+      * @return     a BigDecimal
+      * @exception   SqlValueException
+      */
+    public BigDecimal asBigDecimal(int scale) throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isBigDecimal())
+                return ((BigDecimal) valueObject).setScale(scale);
+            else if (
+                isString()
+                    || isDouble()
+                    || isFloat()
+                    || isInt()
+                    || isLong()
+                    || isShort()
+                    || isByte())
+                return new BigDecimal(asString()).setScale(scale);
+            else
+                return null;
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Bad conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asBoolean
+      *
+      * @return     a boolean
+      * @exception   SqlValueException
+      */
+    public boolean asBoolean() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return false;
+            else if (isBoolean())
+                return ((Boolean) valueObject).booleanValue();
+
+            String check = asString();
+            if (check == null)
+                return false;
+            else if (isTrue(check))
+                return true;
+            else
+                return false;
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Bad conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asInt
+      *
+      * @return     an int
+      * @exception   SqlValueException
+      */
+    public int asInt() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return 0;
+            else if (isInt())
+                return ((Integer) valueObject).intValue();
+            else if (isString())
+                return Integer.valueOf((String) valueObject).intValue();
+            else if (isLong())
+                return ((Long) valueObject).intValue();
+            else if (isDouble())
+                return ((Double) valueObject).intValue();
+            else if (isFloat())
+                return ((Float) valueObject).intValue();
+            else if (isBigDecimal())
+                return ((BigDecimal) valueObject).intValue();
+            else
+                return Integer.valueOf(asString()).intValue();
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Bad conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a Integer Ojbect
+      *
+      * @return     an Integer
+      * @exception   SqlValueException
+      */
+    public Integer asIntegerObj() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isInt())
+                return ((Integer) valueObject);
+            else if (
+                isString()
+                    || isDouble()
+                    || isFloat()
+                    || isBigDecimal()
+                    || isLong()
+                    || isShort()
+                    || isByte())
+                return new Integer(asString());
+            else
+                throw new SqlValueException("Invalid type for Integer");
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Illegal conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asByte
+      *
+      * @return     a byte
+      * @exception   SqlValueException
+      */
+    public byte asByte() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return 0;
+            else if (isByte())
+                return ((Byte) valueObject).byteValue();
+            else if (isString())
+                return Integer.valueOf((String) valueObject).byteValue();
+            else if (isShort())
+                return ((Short) valueObject).byteValue();
+            else if (isInt())
+                return ((Integer) valueObject).byteValue();
+            else if (isLong())
+                return ((Long) valueObject).byteValue();
+            else if (isDouble())
+                return ((Double) valueObject).byteValue();
+            else if (isFloat())
+                return ((Float) valueObject).byteValue();
+            else if (isBigDecimal())
+                return ((BigDecimal) valueObject).byteValue();
+            else
+                return Integer.valueOf(asString()).byteValue();
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Bad conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a Byte Object
+      *
+      * @return     a Byte
+      * @exception   SqlValueException
+      */
+    public Byte asByteObj() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isByte())
+                return ((Byte) valueObject);
+            else if (
+                isString()
+                    || isDouble()
+                    || isFloat()
+                    || isInt()
+                    || isLong()
+                    || isShort()
+                    || isBigDecimal())
+                return new Byte(asString());
+            else
+                throw new SqlValueException("Invalid type for Byte");
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Illegal conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asBytes
+      *
+      * @return     a byte array
+      * @exception   SqlValueException
+      */
+    public byte[] asBytes() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isBytes())
+                return (byte[]) valueObject;
+            else if (isString())
+                return ((String) valueObject).getBytes();
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Bad conversion: " + e.toString());
+        }
+        return null;
+    }
+
+    /**
+      * Get the value as a asShort
+      *
+      * @return     a short
+      * @exception   SqlValueException
+      */
+    public short asShort() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return 0;
+            else if (isShort())
+                return ((Short) valueObject).shortValue();
+            else if (isString())
+                return Integer.valueOf((String) valueObject).shortValue();
+            else if (isInt())
+                return ((Integer) valueObject).shortValue();
+            else if (isLong())
+                return ((Long) valueObject).shortValue();
+            else if (isDouble())
+                return ((Double) valueObject).shortValue();
+            else if (isFloat())
+                return ((Float) valueObject).shortValue();
+            else if (isBigDecimal())
+                return ((BigDecimal) valueObject).shortValue();
+            else
+                return Integer.valueOf(asString()).shortValue();
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Bad conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a Short Object
+      *
+      * @return     a Short
+      * @exception   SqlValueException
+      */
+    public Short asShortObj() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isShort())
+                return ((Short) valueObject);
+            else if (
+                isString()
+                    || isDouble()
+                    || isFloat()
+                    || isInt()
+                    || isLong()
+                    || isBigDecimal()
+                    || isByte())
+                return new Short(asString());
+            else
+                throw new SqlValueException("Invalid type for Short");
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Illegal conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asLong
+      *
+      * @return     a long
+      * @exception   SqlValueException
+      */
+    public long asLong() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return 0;
+            else if (isLong())
+                return ((Long) valueObject).longValue();
+            else if (isString())
+                return Integer.valueOf((String) valueObject).longValue();
+            else if (isShort())
+                return ((Short) valueObject).longValue();
+            else if (isInt())
+                return ((Integer) valueObject).longValue();
+            else if (isDouble())
+                return ((Double) valueObject).longValue();
+            else if (isFloat())
+                return ((Float) valueObject).longValue();
+            else if (isBigDecimal())
+                return ((BigDecimal) valueObject).longValue();
+            else
+                return Integer.valueOf(asString()).longValue();
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Bad conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a Long Object
+      *
+      * @return     a Long
+      * @exception   SqlValueException
+      */
+    public Long asLongObj() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isLong())
+                return ((Long) valueObject);
+            else if (
+                isString()
+                    || isDouble()
+                    || isFloat()
+                    || isInt()
+                    || isBigDecimal()
+                    || isShort()
+                    || isByte())
+                return new Long(asString());
+            else
+                throw new SqlValueException("Invalid type for Long");
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Illegal conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asDouble
+      *
+      * @return     a double
+      * @exception   SqlValueException
+      */
+    public double asDouble() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return 0.0D;
+            else if (isDouble())
+                return ((Double) valueObject).doubleValue();
+            else if (isString())
+                return Integer.valueOf((String) valueObject).doubleValue();
+            else if (isShort())
+                return ((Short) valueObject).doubleValue();
+            else if (isInt())
+                return ((Integer) valueObject).doubleValue();
+            else if (isLong())
+                return ((Long) valueObject).doubleValue();
+            else if (isFloat())
+                return ((Float) valueObject).doubleValue();
+            else if (isBigDecimal())
+                return ((BigDecimal) valueObject).doubleValue();
+            else
+                return Integer.valueOf(asString()).doubleValue();
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Bad conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a Double Object
+      *
+      * @return     a Double
+      * @exception   SqlValueException
+      */
+    public Double asDoubleObj() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isDouble())
+                return ((Double) valueObject);
+            else if (
+                isString()
+                    || isBigDecimal()
+                    || isFloat()
+                    || isInt()
+                    || isLong()
+                    || isShort()
+                    || isByte())
+                return new Double(asString());
+            else
+                throw new SqlValueException("Invalid type for Double");
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Illegal conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asFloat
+      *
+      * @return     a float
+      * @exception   SqlValueException
+      */
+    public float asFloat() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return 0.0F;
+            else if (isFloat())
+                return ((Float) valueObject).floatValue();
+            else if (isString())
+                return Integer.valueOf((String) valueObject).floatValue();
+            else if (isShort())
+                return ((Short) valueObject).floatValue();
+            else if (isInt())
+                return ((Integer) valueObject).floatValue();
+            else if (isLong())
+                return ((Long) valueObject).floatValue();
+            else if (isDouble())
+                return ((Double) valueObject).floatValue();
+            else if (isBigDecimal())
+                return ((BigDecimal) valueObject).floatValue();
+            else
+                return Integer.valueOf(asString()).floatValue();
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Bad conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a Float Obj
+      *
+      * @return     a Float
+      * @exception   SqlValueException
+      */
+    public Float asFloatObj() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isFloat())
+                return ((Float) valueObject);
+            else if (
+                isString()
+                    || isDouble()
+                    || isBigDecimal()
+                    || isInt()
+                    || isLong()
+                    || isShort()
+                    || isByte())
+                return new Float(asString());
+            else
+                throw new SqlValueException("Invalid type for Float");
+        } catch (Exception e)
+        {
+            throw new SqlValueException("Illegal conversion: " + e.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asTime
+      *
+      * @return     a Time
+      * @exception   SqlValueException
+      */
+    public Time asTime() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isTime())
+                return (Time) valueObject;
+
+            Calendar cal = Calendar.getInstance();
+            if (isTimestamp())
+            {
+                cal.setTime((Timestamp) valueObject);
+                return new Time(cal.getTime().getTime());
+            } else if (isUtilDate())
+            {
+                cal.setTime((java.util.Date) valueObject);
+                return new Time(cal.getTime().getTime());
+            } else if (isString())
+                return Time.valueOf((String) valueObject);
+            else
+                return Time.valueOf(asString());
+        } catch (IllegalArgumentException a)
+        {
+            throw new SqlValueException("Bad date value - Java Time Objects cannot be 
+earlier than 1/1/70");
+        } catch (Exception b)
+        {
+            throw new SqlValueException("Bad conversion: " + b.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asTimestamp
+      *
+      * @return     a Timestamp
+      * @exception   SqlValueException
+      */
+    public Timestamp asTimestamp() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isTimestamp())
+                return (Timestamp) valueObject;
+
+            if (isTime())
+            {
+                Calendar cal = Calendar.getInstance();
+                cal.setTime((Time) valueObject);
+                return new Timestamp(cal.getTime().getTime());
+            } else if (isUtilDate())
+            {
+                return new Timestamp(((java.util.Date) valueObject).getTime());
+            } else if (isString())
+                return Timestamp.valueOf((String) valueObject);
+            else
+                return Timestamp.valueOf(asString());
+        } catch (IllegalArgumentException a)
+        {
+            throw new SqlValueException("Bad date value - Java Timestamp Objects 
+cannot be earlier than 1/1/70");
+        } catch (Exception b)
+        {
+            throw new SqlValueException("Bad conversion: " + b.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asDate
+      *
+      * @return     a java.sql.Date
+      * @exception   SqlValueException
+      */
+    public java.sql.Date asDate() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isDate())
+                return (java.sql.Date) valueObject;
+
+            Calendar cal = Calendar.getInstance();
+            if (isTimestamp())
+            {
+                Timestamp ts = (Timestamp) valueObject;
+                long date = ts.getTime();
+                int nanos = ts.getNanos();
+                return new java.sql.Date(date + (nanos / 1000000));
+            } else if (isTime())
+            {
+                cal.setTime((Time) valueObject);
+                return java.sql.Date.valueOf(
+                    cal.get(Calendar.YEAR)
+                        + "-"
+                        + (cal.get(Calendar.MONTH) + 1)
+                        + "-"
+                        + cal.get(Calendar.DAY_OF_MONTH));
+            } else if (isUtilDate())
+            {
+                cal.setTime((java.util.Date) valueObject);
+                return java.sql.Date.valueOf(
+                    cal.get(Calendar.YEAR)
+                        + "-"
+                        + (cal.get(Calendar.MONTH) + 1)
+                        + "-"
+                        + cal.get(Calendar.DAY_OF_MONTH));
+            } else if (isString())
+                return java.sql.Date.valueOf((String) valueObject);
+            else
+                return java.sql.Date.valueOf(asString());
+        } catch (IllegalArgumentException a)
+        {
+            throw new SqlValueException("Bad date value - Java Timestamp Objects 
+cannot be earlier than 1/1/70");
+        } catch (Exception b)
+        {
+            throw new SqlValueException("Bad conversion: " + b.toString());
+        }
+    }
+
+    /**
+      * Get the value as a asUtilDate
+      *
+      * @return     a java.util.Date
+      * @exception   SqlValueException
+      */
+    public java.util.Date asUtilDate() throws SqlValueException
+    {
+        try
+        {
+            if (isNull())
+                return null;
+            else if (isUtilDate())
+                return (java.util.Date) valueObject;
+
+            Calendar cal = Calendar.getInstance();
+            if (isTimestamp())
+            {
+                Timestamp ts = (Timestamp) valueObject;
+                long date = ts.getTime();
+                int nanos = ts.getNanos();
+                return new java.util.Date(date + (nanos / 1000000));
+            } else if (isTime())
+            {
+                cal.setTime((Time) valueObject);
+                return java.sql.Date.valueOf(
+                    cal.get(Calendar.YEAR)
+                        + "-"
+                        + (cal.get(Calendar.MONTH) + 1)
+                        + "-"
+                        + cal.get(Calendar.DAY_OF_MONTH));
+            } else if (isUtilDate())
+            {
+                cal.setTime((java.util.Date) valueObject);
+                return java.sql.Date.valueOf(
+                    cal.get(Calendar.YEAR)
+                        + "-"
+                        + (cal.get(Calendar.MONTH) + 1)
+                        + "-"
+                        + cal.get(Calendar.DAY_OF_MONTH));
+            } else
+            {
+                return null;
+            }
+        } catch (IllegalArgumentException a)
+        {
+            throw new SqlValueException("Bad date value - Java java.util.Date Objects 
+cannot be earlier than 1/1/70");
+        } catch (Exception b)
+        {
+            throw new SqlValueException("Bad conversion: " + b.toString());
+        }
+    }
+
+    /**
+      * Is the value a isBigDecimal
+      *
+      * @return     true if BigDecimal
+      */
+    public boolean isBigDecimal()
+    {
+        return valueObject instanceof BigDecimal;
+    }
+
+    /**
+      * Is the value a isByte
+      *
+      * @return     true if is Byte
+      */
+    public boolean isByte()
+    {
+        return valueObject instanceof Byte;
+    }
+
+    /**
+      * Is the value a isBytes
+      *
+      * @return     true if is byte[]
+      */
+    public boolean isBytes()
+    {
+        return valueObject instanceof byte[];
+    }
+
+    /**
+      * Is the value a isDate
+      *
+      * @return     true if is java.sql.Date
+      */
+    public boolean isDate()
+    {
+        return valueObject instanceof java.sql.Date;
+    }
+
+    /**
+      * Is the value a isShort
+      *
+      * @return     true if is Short
+      */
+    public boolean isShort()
+    {
+        return valueObject instanceof Short;
+    }
+
+    /**
+      * Is the value a isInt
+      *
+      * @return     true if is Integer
+      */
+    public boolean isInt()
+    {
+        return valueObject instanceof Integer;
+    }
+
+    /**
+      * Is the value a isLong
+      *
+      * @return     true if is Long
+      */
+    public boolean isLong()
+    {
+        return valueObject instanceof Long;
+    }
+
+    /**
+      * Is the value a isDouble
+      *
+      * @return     true if is Double
+      */
+    public boolean isDouble()
+    {
+        return valueObject instanceof Double;
+    }
+
+    /**
+      * Is the value a isFloat
+      *
+      * @return     true if is Float
+      */
+    public boolean isFloat()
+    {
+        return valueObject instanceof Float;
+    }
+
+    /**
+      * Is the value a isBoolean
+      *
+      * @return     true if is Boolean
+      */
+    public boolean isBoolean()
+    {
+        return valueObject instanceof Boolean;
+    }
+
+    /**
+      * Is the value a isNull
+      *
+      * @return     true if is null
+      */
+    public boolean isNull()
+    {
+        return valueObject == null;
+    }
+
+    /**
+      * Is the value a isString
+      *
+      * @return     true if is String
+      */
+    public boolean isString()
+    {
+        return valueObject instanceof String;
+    }
+
+    /**
+      * Is the value a isTime
+      *
+      * @return     true if is java.sql.Time
+      */
+    public boolean isTime()
+    {
+        return valueObject instanceof java.sql.Time;
+    }
+
+    /**
+      * Is the value a isTimestamp
+      *
+      * @return     true if is java.sql.Timestamp
+      */
+    public boolean isTimestamp()
+    {
+        return valueObject instanceof java.sql.Timestamp;
+    }
+
+    /**
+      * Is the value a isUtilDate
+      *
+      * @return     true if is java.util.Date
+      */
+    public boolean isUtilDate()
+    {
+        return valueObject instanceof java.util.Date;
+    }
+
+    /**
+      * Return the type of this value
+      *
+      * @return     the type of this value
+      */
+    public int type()
+    {
+        return this.type;
+    }
+
+    /**
+     * @return true if (true || t | yes | 1)
+     */
+    private boolean isTrue(String value)
+    {
+        return (
+            value.equalsIgnoreCase("true")
+                || value.equalsIgnoreCase("t")
+                || value.equalsIgnoreCase("yes")
+                || value.equals("1"));
+    }
+}
Index: src/java/org/apache/turbine/util/db/SqlValueException.java
===================================================================
RCS file: SqlValueException.java
diff -N SqlValueException.java
--- /dev/null   Mon Jan 13 17:03:52 2003
+++ SqlValueException.java  Mon Jan 13 18:17:02 2003
@@ -0,0 +1,81 @@
+package org.apache.turbine.util.db;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and 
+ *    "Apache Turbine" must not be used to endorse or promote products 
+ *    derived from this software without prior written permission. For 
+ *    written permission, please contact [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache Turbine", nor may "Apache" appear in their name, without 
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * Exception thrown when a Java type and a SQL type cannot be used together.
+ * 
+ * @author <A HREF="mailto:[EMAIL PROTECTED]";>Chris Felaco</A>
+ * @version $Id$
+ */
+public class SqlValueException extends Exception
+{
+
+    /**
+     * Constructor for SQLValueException.
+     */
+    public SqlValueException()
+    {
+        super();
+    }
+
+    /**
+     * Constructor for SQLValueException.
+     * @param s
+     */
+    public SqlValueException(String s)
+    {
+        super(s);
+    }
+}


--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to